[{"data":1,"prerenderedAt":1180},["ShallowReactive",2],{"navigation_docs_en":3,"-en-database-overview":342,"-en-database-overview-surround":1175},[4,45,61,96,132,166,196,217,241,265],{"title":5,"icon":6,"path":7,"stem":8,"children":9,"page":44},"Getting Started","i-lucide-rocket","\u002Fen\u002Fgetting-started","en\u002F1.getting-started",[10,15,20,24,29,34,39],{"title":11,"path":12,"stem":13,"icon":14},"Introduction","\u002Fen\u002Fgetting-started\u002Fintroduction","en\u002F1.getting-started\u002F1.introduction","i-lucide-house",{"title":16,"path":17,"stem":18,"icon":19},"Coming from Laravel","\u002Fen\u002Fgetting-started\u002Fcoming-from-laravel","en\u002F1.getting-started\u002F2.coming-from-laravel","i-lucide-arrow-right-left",{"title":21,"path":22,"stem":23,"icon":19},"Coming from Symfony","\u002Fen\u002Fgetting-started\u002Fcoming-from-symfony","en\u002F1.getting-started\u002F3.coming-from-symfony",{"title":25,"path":26,"stem":27,"icon":28},"Installation","\u002Fen\u002Fgetting-started\u002Finstallation","en\u002F1.getting-started\u002F4.installation","i-lucide-download",{"title":30,"path":31,"stem":32,"icon":33},"Your first module","\u002Fen\u002Fgetting-started\u002Ffirst-module","en\u002F1.getting-started\u002F5.first-module","i-lucide-package-plus",{"title":35,"path":36,"stem":37,"icon":38},"Project structure","\u002Fen\u002Fgetting-started\u002Fproject-structure","en\u002F1.getting-started\u002F6.project-structure","i-lucide-folder-tree",{"title":40,"path":41,"stem":42,"icon":43},"The shop sample application","\u002Fen\u002Fgetting-started\u002Fsample-app","en\u002F1.getting-started\u002F7.sample-app","i-lucide-shopping-cart",false,{"title":46,"icon":47,"path":48,"stem":49,"children":50,"page":44},"Reference","i-lucide-book-open","\u002Fen\u002Freference","en\u002F10.reference",[51,56],{"title":52,"path":53,"stem":54,"icon":55},"Configuration","\u002Fen\u002Freference\u002Fconfiguration","en\u002F10.reference\u002F1.configuration","i-lucide-settings",{"title":57,"path":58,"stem":59,"icon":60},"External dependencies","\u002Fen\u002Freference\u002Fdependencies","en\u002F10.reference\u002F2.dependencies","i-lucide-package",{"title":62,"icon":63,"path":64,"stem":65,"children":66,"page":44},"Concepts","i-lucide-lightbulb","\u002Fen\u002Fconcepts","en\u002F2.concepts",[67,72,77,82,86,91],{"title":68,"path":69,"stem":70,"icon":71},"Architecture","\u002Fen\u002Fconcepts\u002Farchitecture","en\u002F2.concepts\u002F1.architecture","i-lucide-layers",{"title":73,"path":74,"stem":75,"icon":76},"Application lifecycle","\u002Fen\u002Fconcepts\u002Fapplication-lifecycle","en\u002F2.concepts\u002F2.application-lifecycle","i-lucide-power",{"title":78,"path":79,"stem":80,"icon":81},"Error model","\u002Fen\u002Fconcepts\u002Ferror-model","en\u002F2.concepts\u002F3.error-model","i-lucide-shield-alert",{"title":52,"path":83,"stem":84,"icon":85},"\u002Fen\u002Fconcepts\u002Fconfiguration","en\u002F2.concepts\u002F4.configuration","i-lucide-settings-2",{"title":87,"path":88,"stem":89,"icon":90},"Codegen pipeline","\u002Fen\u002Fconcepts\u002Fcodegen-pipeline","en\u002F2.concepts\u002F5.codegen-pipeline","i-lucide-file-json",{"title":92,"path":93,"stem":94,"icon":95},"Design patterns","\u002Fen\u002Fconcepts\u002Fdesign-patterns","en\u002F2.concepts\u002F6.design-patterns","i-lucide-puzzle",{"title":97,"icon":98,"path":99,"stem":100,"children":101,"page":44},"HTTP & Routing","i-lucide-globe","\u002Fen\u002Fhttp","en\u002F3.http",[102,107,112,117,122,127],{"title":103,"path":104,"stem":105,"icon":106},"The server core","\u002Fen\u002Fhttp\u002Fserver","en\u002F3.http\u002F1.server","i-lucide-server",{"title":108,"path":109,"stem":110,"icon":111},"The Fiber engine","\u002Fen\u002Fhttp\u002Ffiber","en\u002F3.http\u002F2.fiber","i-lucide-zap",{"title":113,"path":114,"stem":115,"icon":116},"The chi engine","\u002Fen\u002Fhttp\u002Fchi","en\u002F3.http\u002F3.chi","i-lucide-route",{"title":118,"path":119,"stem":120,"icon":121},"Error responses","\u002Fen\u002Fhttp\u002Ferror-responses","en\u002F3.http\u002F4.error-responses","i-lucide-octagon-alert",{"title":123,"path":124,"stem":125,"icon":126},"Validation","\u002Fen\u002Fhttp\u002Fvalidation","en\u002F3.http\u002F5.validation","i-lucide-badge-check",{"title":128,"path":129,"stem":130,"icon":131},"Pagination","\u002Fen\u002Fhttp\u002Fpagination","en\u002F3.http\u002F6.pagination","i-lucide-list-ordered",{"title":133,"icon":134,"path":135,"stem":136,"children":137,"page":44},"Database","i-lucide-database","\u002Fen\u002Fdatabase","en\u002F4.database",[138,142,147,151,156,161],{"title":139,"path":140,"stem":141,"icon":134},"Overview","\u002Fen\u002Fdatabase\u002Foverview","en\u002F4.database\u002F1.overview",{"title":143,"path":144,"stem":145,"icon":146},"pgx","\u002Fen\u002Fdatabase\u002Fpgx","en\u002F4.database\u002F2.pgx","i-lucide-plug",{"title":148,"path":149,"stem":150,"icon":71},"bun","\u002Fen\u002Fdatabase\u002Fbun","en\u002F4.database\u002F3.bun",{"title":152,"path":153,"stem":154,"icon":155},"Transactions","\u002Fen\u002Fdatabase\u002Ftransactions","en\u002F4.database\u002F4.transactions","i-lucide-git-merge",{"title":157,"path":158,"stem":159,"icon":160},"Migrations","\u002Fen\u002Fdatabase\u002Fmigrations","en\u002F4.database\u002F5.migrations","i-lucide-file-stack",{"title":162,"path":163,"stem":164,"icon":165},"Seeders","\u002Fen\u002Fdatabase\u002Fseeding","en\u002F4.database\u002F6.seeding","i-lucide-sprout",{"title":167,"icon":168,"path":169,"stem":170,"children":171,"page":44},"Async & Background","i-lucide-workflow","\u002Fen\u002Fasync","en\u002F5.async",[172,176,181,186,191],{"title":173,"path":174,"stem":175,"icon":131},"Queue","\u002Fen\u002Fasync\u002Fqueue","en\u002F5.async\u002F1.queue",{"title":177,"path":178,"stem":179,"icon":180},"Events","\u002Fen\u002Fasync\u002Fevents","en\u002F5.async\u002F2.events","i-lucide-radio",{"title":182,"path":183,"stem":184,"icon":185},"Outbox","\u002Fen\u002Fasync\u002Foutbox","en\u002F5.async\u002F3.outbox","i-lucide-inbox",{"title":187,"path":188,"stem":189,"icon":190},"Scheduling","\u002Fen\u002Fasync\u002Fscheduler","en\u002F5.async\u002F4.scheduler","i-lucide-calendar-clock",{"title":192,"path":193,"stem":194,"icon":195},"Worker","\u002Fen\u002Fasync\u002Fworker","en\u002F5.async\u002F5.worker","i-lucide-cog",{"title":197,"icon":198,"path":199,"stem":200,"children":201,"page":44},"Security","i-lucide-shield-check","\u002Fen\u002Fsecurity","en\u002F6.security",[202,207,212],{"title":203,"path":204,"stem":205,"icon":206},"Authentication","\u002Fen\u002Fsecurity\u002Fauthentication","en\u002F6.security\u002F1.authentication","i-lucide-key-round",{"title":208,"path":209,"stem":210,"icon":211},"RBAC","\u002Fen\u002Fsecurity\u002Frbac","en\u002F6.security\u002F2.rbac","i-lucide-users",{"title":213,"path":214,"stem":215,"icon":216},"Policies","\u002Fen\u002Fsecurity\u002Fpolicies","en\u002F6.security\u002F3.policies","i-lucide-gavel",{"title":218,"icon":219,"path":220,"stem":221,"children":222,"page":44},"Observability","i-lucide-activity","\u002Fen\u002Fobservability","en\u002F7.observability",[223,226,231,236],{"title":139,"path":224,"stem":225,"icon":219},"\u002Fen\u002Fobservability\u002Foverview","en\u002F7.observability\u002F1.overview",{"title":227,"path":228,"stem":229,"icon":230},"Logging","\u002Fen\u002Fobservability\u002Flogging","en\u002F7.observability\u002F2.logging","i-lucide-scroll-text",{"title":232,"path":233,"stem":234,"icon":235},"OpenTelemetry","\u002Fen\u002Fobservability\u002Fopentelemetry","en\u002F7.observability\u002F3.opentelemetry","i-lucide-radar",{"title":237,"path":238,"stem":239,"icon":240},"Sentry","\u002Fen\u002Fobservability\u002Fsentry","en\u002F7.observability\u002F4.sentry","i-lucide-bug",{"title":242,"icon":243,"path":244,"stem":245,"children":246,"page":44},"Storage & Mail","i-lucide-hard-drive","\u002Fen\u002Fstorage-mail","en\u002F8.storage-mail",[247,251,256,261],{"title":248,"path":249,"stem":250,"icon":243},"Storage","\u002Fen\u002Fstorage-mail\u002Fstorage","en\u002F8.storage-mail\u002F1.storage",{"title":252,"path":253,"stem":254,"icon":255},"Email","\u002Fen\u002Fstorage-mail\u002Fmail","en\u002F8.storage-mail\u002F2.mail","i-lucide-mail",{"title":257,"path":258,"stem":259,"icon":260},"Notifications","\u002Fen\u002Fstorage-mail\u002Fnotifications","en\u002F8.storage-mail\u002F3.notifications","i-lucide-bell",{"title":262,"path":263,"stem":264,"icon":180},"Realtime","\u002Fen\u002Fstorage-mail\u002Frealtime","en\u002F8.storage-mail\u002F4.realtime",{"title":266,"icon":267,"path":268,"stem":269,"children":270,"page":44},"CLI Reference","i-lucide-terminal","\u002Fen\u002Fcli","en\u002F9.cli",[271,274,279,284,289,294,299,303,308,313,318,323,328,333,337],{"title":139,"path":272,"stem":273,"icon":267},"\u002Fen\u002Fcli\u002Foverview","en\u002F9.cli\u002F1.overview",{"title":275,"path":276,"stem":277,"icon":278},"add db","\u002Fen\u002Fcli\u002Fadd-db","en\u002F9.cli\u002F10.add-db","i-lucide-database-zap",{"title":280,"path":281,"stem":282,"icon":283},"add compose \u002F add docker","\u002Fen\u002Fcli\u002Fadd-compose","en\u002F9.cli\u002F11.add-compose","i-lucide-container",{"title":285,"path":286,"stem":287,"icon":288},"add mail","\u002Fen\u002Fcli\u002Fadd-mail","en\u002F9.cli\u002F12.add-mail","i-lucide-mail-plus",{"title":290,"path":291,"stem":292,"icon":293},"add notification","\u002Fen\u002Fcli\u002Fadd-notification","en\u002F9.cli\u002F13.add-notification","i-lucide-bell-plus",{"title":295,"path":296,"stem":297,"icon":298},"add realtime","\u002Fen\u002Fcli\u002Fadd-realtime","en\u002F9.cli\u002F14.add-realtime","i-lucide-radio-tower",{"title":300,"path":301,"stem":302,"icon":165},"add seeder","\u002Fen\u002Fcli\u002Fadd-seeder","en\u002F9.cli\u002F15.add-seeder",{"title":304,"path":305,"stem":306,"icon":307},"new project","\u002Fen\u002Fcli\u002Fnew-project","en\u002F9.cli\u002F2.new-project","i-lucide-folder-plus",{"title":309,"path":310,"stem":311,"icon":312},"new module","\u002Fen\u002Fcli\u002Fnew-module","en\u002F9.cli\u002F3.new-module","i-lucide-blocks",{"title":314,"path":315,"stem":316,"icon":317},"add surface","\u002Fen\u002Fcli\u002Fadd-surface","en\u002F9.cli\u002F4.add-surface","i-lucide-layers-2",{"title":319,"path":320,"stem":321,"icon":322},"add core","\u002Fen\u002Fcli\u002Fadd-core","en\u002F9.cli\u002F5.add-core","i-lucide-box",{"title":324,"path":325,"stem":326,"icon":327},"add handler","\u002Fen\u002Fcli\u002Fadd-handler","en\u002F9.cli\u002F6.add-handler","i-lucide-webhook",{"title":329,"path":330,"stem":331,"icon":332},"new migration","\u002Fen\u002Fcli\u002Fnew-migration","en\u002F9.cli\u002F7.new-migration","i-lucide-file-plus",{"title":334,"path":335,"stem":336,"icon":195},"worker generators","\u002Fen\u002Fcli\u002Fworker-generators","en\u002F9.cli\u002F8.worker-generators",{"title":338,"path":339,"stem":340,"icon":341},"upgrade templates","\u002Fen\u002Fcli\u002Fupgrade-templates","en\u002F9.cli\u002F9.upgrade-templates","i-lucide-refresh-cw",{"id":343,"title":139,"body":344,"description":1168,"extension":1169,"links":1170,"meta":1171,"navigation":1172,"path":140,"seo":1173,"stem":141,"__hash__":1174},"docs_en\u002Fen\u002F4.database\u002F1.overview.md",{"type":345,"value":346,"toc":1160},"minimark",[347,368,413,424,453,457,462,510,517,650,682,686,690,725,745,800,822,825,896,918,921,925,941,1062,1069,1073,1108,1115,1119,1156],[348,349,350,354,355,358,359,362,363,367],"p",{},[351,352,353],"code",{},"dbx"," is the kit's database-agnostic contract. It defines exactly two things: ",[351,356,357],{},"Config",", which describes a PostgreSQL connection, and the ",[351,360,361],{},"Transactor"," interface services depend on to span multiple repositories in one transaction. ",[364,365,366],"strong",{},"It has no database driver dependency of its own",": the actual implementation lives in a subpackage, and you pick one by importing it:",[369,370,371,394],"ul",{},[372,373,374,382,383,386,387,389,390,393],"li",{},[375,376,377],"a",{"href":144},[364,378,379],{},[351,380,381],{},"dbx\u002Fpg",": the pgx-native stack (the default): pool construction, the ",[351,384,385],{},"DBTX"," query executor, and a ",[351,388,361],{}," backed by ",[351,391,392],{},"pgx.Tx",".",[372,395,396,403,404,409,410,393],{},[375,397,398],{"href":149},[364,399,400],{},[351,401,402],{},"dbx\u002Fbunx",": an optional adapter for projects that prefer the ",[375,405,148],{"href":406,"rel":407},"https:\u002F\u002Fbun.uptrace.dev",[408],"nofollow"," query builder, backed by ",[351,411,412],{},"bun.Tx",[348,414,415,416,419,420,423],{},"Only one is ever linked into a given binary. Your service and repository layers depend on ",[351,417,418],{},"dbx.Transactor"," and ",[351,421,422],{},"dbx.Config",", never on the concrete implementation. That is why a service's code is identical to the letter whether pgx or bun runs underneath.",[425,426,431],"pre",{"className":427,"code":428,"language":429,"meta":430,"style":430},"language-go shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","import \"github.com\u002Fgp-system\u002Fgpsystem\u002Fdbx\"\n","go","",[351,432,433],{"__ignoreMap":430},[434,435,438,442,446,450],"span",{"class":436,"line":437},"line",1,[434,439,441],{"class":440},"s7zQu","import",[434,443,445],{"class":444},"sMK4o"," \"",[434,447,449],{"class":448},"sBMFI","github.com\u002Fgp-system\u002Fgpsystem\u002Fdbx",[434,451,452],{"class":444},"\"\n",[454,455,357],"h2",{"id":456},"config",[348,458,459,461],{},[351,460,422],{}," describes a single PostgreSQL connection. You compose it into the application's config struct under a prefix:",[425,463,465],{"className":427,"code":464,"language":429,"meta":430,"style":430},"type Config struct {\n    DB dbx.Config `envPrefix:\"DB_\"`\n}\n",[351,466,467,481,504],{"__ignoreMap":430},[434,468,469,472,475,478],{"class":436,"line":437},[434,470,471],{"class":444},"type",[434,473,474],{"class":448}," Config",[434,476,477],{"class":444}," struct",[434,479,480],{"class":444}," {\n",[434,482,484,488,490,492,494,497,501],{"class":436,"line":483},2,[434,485,487],{"class":486},"sTEyZ","    DB ",[434,489,353],{"class":448},[434,491,393],{"class":444},[434,493,357],{"class":448},[434,495,496],{"class":444}," `",[434,498,500],{"class":499},"sfazB","envPrefix:\"DB_\"",[434,502,503],{"class":444},"`\n",[434,505,507],{"class":436,"line":506},3,[434,508,509],{"class":444},"}\n",[348,511,512,513,516],{},"which maps to the following environment variables (a generated project's ",[351,514,515],{},".env.example"," lists exactly these):",[518,519,520,536],"table",{},[521,522,523],"thead",{},[524,525,526,530,533],"tr",{},[527,528,529],"th",{},"Env variable",[527,531,532],{},"Field",[527,534,535],{},"Default",[537,538,539,557,574,589,603,616,633],"tbody",{},[524,540,541,547,552],{},[542,543,544],"td",{},[351,545,546],{},"DB_HOST",[542,548,549],{},[351,550,551],{},"Host",[542,553,554],{},[351,555,556],{},"localhost",[524,558,559,564,569],{},[542,560,561],{},[351,562,563],{},"DB_PORT",[542,565,566],{},[351,567,568],{},"Port",[542,570,571],{},[351,572,573],{},"5432",[524,575,576,581,586],{},[542,577,578],{},[351,579,580],{},"DB_USER",[542,582,583],{},[351,584,585],{},"User",[542,587,588],{},"required",[524,590,591,596,601],{},[542,592,593],{},[351,594,595],{},"DB_PASSWORD",[542,597,598],{},[351,599,600],{},"Password",[542,602,588],{},[524,604,605,610,614],{},[542,606,607],{},[351,608,609],{},"DB_NAME",[542,611,612],{},[351,613,133],{},[542,615,588],{},[524,617,618,623,628],{},[542,619,620],{},[351,621,622],{},"DB_SSLMODE",[542,624,625],{},[351,626,627],{},"SSLMode",[542,629,630],{},[351,631,632],{},"disable",[524,634,635,640,645],{},[542,636,637],{},[351,638,639],{},"DB_MAX_CONNS",[542,641,642],{},[351,643,644],{},"MaxConns",[542,646,647],{},[351,648,649],{},"10",[348,651,652,653,656,657,660,661,667,668,673,674,677,678,681],{},"The ",[351,654,655],{},"DSN()"," method renders the config as a ",[351,658,659],{},"postgres:\u002F\u002F"," connection URL. It is consumed by ",[375,662,664],{"href":663},"\u002Fen\u002Fdatabase\u002Fpgx#pool",[351,665,666],{},"pg.NewPool"," and by the generated ",[375,669,670],{"href":158},[351,671,672],{},"cmd\u002Fmigrate"," binary alike. Loading is done by ",[375,675,676],{"href":83},"envconf",", with ",[351,679,680],{},".env"," support.",[683,684,685],"note",{},"There is no intermediate config file: the env variables load straight into a typed struct, and a missing required value fails at startup, not on the first query.",[454,687,689],{"id":688},"named-connections","Named connections",[348,691,692,693,696,697,700,701,705,706,708,709,712,713,716,717,720,721,724],{},"A module's default connection, ",[351,694,695],{},"cfg.DB"," composed under ",[351,698,699],{},"DB_*",", covers the common case: one project, one database, one connector. When a module genuinely needs a second connection (an analytics warehouse, a legacy database, a read replica reached through its own pool), the ",[375,702,703],{"href":276},[351,704,275],{}," generator adds it: its own ",[351,707,422],{}," under ",[351,710,711],{},"DB_\u003CNAME>_*",", its own pgx pool, and ",[351,714,715],{},"\u003CName>DB"," \u002F ",[351,718,719],{},"\u003CName>Transactor"," fields on the module's ",[351,722,723],{},"Dependencies",", independent of the default connection and of each other.",[348,726,727,728,730,731,733,734,737,738,740,741,744],{},"The connector (",[351,729,143],{}," or ",[351,732,148],{},") is chosen ",[364,735,736],{},"per connection",", not per project: a module can mix a pgx-native default with a bun-backed named connection, or the reverse. This follows directly from the ",[351,739,361],{}," boundary above: ",[351,742,743],{},"WithinTransaction"," on one connection never spans another, so there is no cross-connection transaction to keep consistent, and no reason to force every connection onto the same stack.",[425,746,748],{"className":427,"code":747,"language":429,"meta":430,"style":430},"type Config struct {\n    DB          dbx.Config `envPrefix:\"DB_\"`\n    DBAnalytics dbx.Config `envPrefix:\"DB_ANALYTICS_\"`\n}\n",[351,749,750,760,777,795],{"__ignoreMap":430},[434,751,752,754,756,758],{"class":436,"line":437},[434,753,471],{"class":444},[434,755,474],{"class":448},[434,757,477],{"class":444},[434,759,480],{"class":444},[434,761,762,765,767,769,771,773,775],{"class":436,"line":483},[434,763,764],{"class":486},"    DB          ",[434,766,353],{"class":448},[434,768,393],{"class":444},[434,770,357],{"class":448},[434,772,496],{"class":444},[434,774,500],{"class":499},[434,776,503],{"class":444},[434,778,779,782,784,786,788,790,793],{"class":436,"line":506},[434,780,781],{"class":486},"    DBAnalytics ",[434,783,353],{"class":448},[434,785,393],{"class":444},[434,787,357],{"class":448},[434,789,496],{"class":444},[434,791,792],{"class":499},"envPrefix:\"DB_ANALYTICS_\"",[434,794,503],{"class":444},[434,796,798],{"class":436,"line":797},4,[434,799,509],{"class":444},[348,801,802,808,809,812,813,816,817,821],{},[375,803,805],{"href":804},"\u002Fen\u002Fcli\u002Fadd-surface#binding-the-repository-to-a-named-connection",[351,806,807],{},"add surface --db"," binds the module's shared repository skeleton to a named connection, splitting the ",[351,810,811],{},"repository\u002F"," directory into ",[351,814,815],{},"repository\u002F\u003Cname>\u002F",". Without it the module keeps the flat layout. ",[375,818,819],{"href":158},[351,820,672],{}," only ever targets the default connection.",[454,823,361],{"id":824},"transactor",[425,826,828],{"className":427,"code":827,"language":429,"meta":430,"style":430},"type Transactor interface {\n    WithinTransaction(ctx context.Context, fn func(ctx context.Context) error) error\n}\n",[351,829,830,842,892],{"__ignoreMap":430},[434,831,832,834,837,840],{"class":436,"line":437},[434,833,471],{"class":444},[434,835,836],{"class":448}," Transactor",[434,838,839],{"class":444}," interface",[434,841,480],{"class":444},[434,843,844,848,851,855,858,860,863,866,869,872,874,876,878,880,883,887,889],{"class":436,"line":483},[434,845,847],{"class":846},"s2Zo4","    WithinTransaction",[434,849,850],{"class":444},"(",[434,852,854],{"class":853},"sHdIc","ctx",[434,856,857],{"class":448}," context",[434,859,393],{"class":444},[434,861,862],{"class":448},"Context",[434,864,865],{"class":444},",",[434,867,868],{"class":853}," fn",[434,870,871],{"class":444}," func(",[434,873,854],{"class":853},[434,875,857],{"class":448},[434,877,393],{"class":444},[434,879,862],{"class":448},[434,881,882],{"class":444},")",[434,884,886],{"class":885},"spNyl"," error",[434,888,882],{"class":444},[434,890,891],{"class":885}," error\n",[434,893,894],{"class":436,"line":506},[434,895,509],{"class":444},[348,897,898,899,902,903,905,906,730,909,911,912,915,916,393],{},"This is the single interface application code manages transactions through. The transaction is carried by the context, so every database call inside ",[351,900,901],{},"fn",", through ",[351,904,381],{},"'s ",[351,907,908],{},"DB",[351,910,402],{},"'s resolvers, joins it automatically, without the repositories knowing about it. Commit on ",[351,913,914],{},"nil",", rollback on error or panic; a nested call joins the outer transaction. The full semantics and the pattern are covered on ",[375,917,152],{"href":153},[348,919,920],{},"The transaction travels in the context, not in a global connection manager.",[454,922,924],{"id":923},"which-one-to-pick-pgx-or-bun","Which one to pick: pgx or bun?",[348,926,927,928,931,932,935,936,938,939,393],{},"The choice is ",[364,929,930],{},"per project and made at generation time"," (",[351,933,934],{},"--db pgx|bun",", default ",[351,937,143],{},"); the manifest records it and every later generator follows it: see ",[375,940,304],{"href":305},[518,942,943,959],{},[521,944,945],{},[524,946,947,949,954],{},[527,948],{},[527,950,951,953],{},[351,952,381],{}," (pgx)",[527,955,956,958],{},[351,957,402],{}," (bun)",[537,960,961,990,1015,1037,1051],{},[524,962,963,966,979],{},[542,964,965],{},"Writing queries",[542,967,968,969,972,973,972,976,882],{},"hand-written SQL (",[351,970,971],{},"Exec","\u002F",[351,974,975],{},"Query",[351,977,978],{},"QueryRow",[542,980,981,982,985,986,989],{},"bun query builder (",[351,983,984],{},"NewSelect",", ",[351,987,988],{},"NewInsert",", …) + raw SQL escape hatch",[524,991,992,995,1006],{},[542,993,994],{},"Returned types",[542,996,997,985,1000,985,1003],{},[351,998,999],{},"pgconn.CommandTag",[351,1001,1002],{},"pgx.Rows",[351,1004,1005],{},"pgx.Row",[542,1007,1008,1011,1012],{},[351,1009,1010],{},"bun.IDB",", bun models, ",[351,1013,1014],{},"sql.Result",[524,1016,1017,1020,1026],{},[542,1018,1019],{},"sqlc",[542,1021,1022,1023,1025],{},"directly compatible (",[351,1024,385],{}," is identical)",[542,1027,1028,1029,1032,1033,1036],{},"in ",[351,1030,1031],{},"database\u002Fsql"," mode, through the ",[351,1034,1035],{},"Conn"," resolver",[524,1038,1039,1042,1047],{},[542,1040,1041],{},"Transaction carrier",[542,1043,1044,1046],{},[351,1045,392],{}," in the context",[542,1048,1049,1046],{},[351,1050,412],{},[524,1052,1053,1056,1059],{},[542,1054,1055],{},"Good when",[542,1057,1058],{},"you want full control over the SQL, minimal layers",[542,1060,1061],{},"struct-based models and query-builder comfort",[348,1063,1064,1065,1068],{},"Rule of thumb: if you like writing SQL, stay with pgx: fewer layers, fewer surprises. If you want a query builder with struct-based models, bun will feel familiar, but it is ",[375,1066,1067],{"href":149},"not an ActiveRecord\u002FEloquent-style ORM",", and that is worth knowing up front.",[454,1070,1072],{"id":1071},"deliberately-no-orm-abstraction","Deliberately no ORM abstraction",[348,1074,1075,1076,1080,1081,1083,1084,1087,1088,1090,1091,985,1093,1090,1095,1097,1098,1100,1101,1103,1104,1107],{},"The kit's principle applies here too: ",[375,1077,1079],{"href":1078},"\u002Fen\u002Fgetting-started\u002Fintroduction#it-does-not-hide-your-dependencies","centralize, don't abstract",". ",[351,1082,353],{}," does ",[364,1085,1086],{},"not"," define a common query interface over the two stacks. ",[351,1089,381],{}," returns ",[351,1092,1002],{},[351,1094,402],{},[351,1096,1010],{},". The upstream pgx and bun documentation, examples and Stack Overflow answers apply to your project unchanged. The common denominator is deliberately minimal: the connection description (",[351,1099,357],{},") and the transaction boundary (",[351,1102,361],{},"), because those two are what the ",[364,1105,1106],{},"service layer"," needs to depend on.",[348,1109,1110,1111,1114],{},"Schema management follows from this too: there is no schema builder, and ",[375,1112,1113],{"href":158},"migrations"," are plain, embedded SQL files.",[454,1116,1118],{"id":1117},"pages-in-this-section","Pages in this section",[369,1120,1121,1131,1136,1148],{},[372,1122,1123,1125,1126,985,1128,1130],{},[375,1124,143],{"href":144},": the default stack: pool, ",[351,1127,385],{},[351,1129,908],{},", repositories",[372,1132,1133,1135],{},[375,1134,148],{"href":149},": the optional query builder adapter",[372,1137,1138,1140,1141,1143,1144,1147],{},[375,1139,152],{"href":153},": the ",[351,1142,361],{}," pattern in depth, with the ",[351,1145,1146],{},"PlaceOrder"," example",[372,1149,1150,1152,1153,1155],{},[375,1151,157],{"href":158},": numbered SQL files, embedded, with a project-owned ",[351,1154,672],{}," binary",[1157,1158,1159],"style",{},"html pre.shiki code .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .sHdIc, html code.shiki .sHdIc{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#EEFFFF;--shiki-default-font-style:italic;--shiki-dark:#BABED8;--shiki-dark-font-style:italic}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}",{"title":430,"searchDepth":483,"depth":483,"links":1161},[1162,1163,1164,1165,1166,1167],{"id":456,"depth":483,"text":357},{"id":688,"depth":483,"text":689},{"id":824,"depth":483,"text":361},{"id":923,"depth":483,"text":924},{"id":1071,"depth":483,"text":1072},{"id":1117,"depth":483,"text":1118},"The dbx package, the database-agnostic contract your code depends on, and the two implementations you choose by import.","md",null,{},{"icon":134},{"title":139,"description":1168},"kUcvED3tHy79xna0cdLJZ9TgmoivdzqEyQdO_UTdcxg",[1176,1178],{"title":128,"path":129,"stem":130,"description":1177,"icon":131,"children":-1},"Offset and cursor (keyset) pagination with the paginate package, normalized parameters, typed page wrappers, opaque cursors.",{"title":143,"path":144,"stem":145,"description":1179,"icon":146,"children":-1},"The pgx-native database stack: the pool, the DBTX query surface and the context-aware DB executor.",1784668709133]