[{"data":1,"prerenderedAt":284},["ShallowReactive",2],{"docs-\u002Fdocs\u002Fmain\u002Fdatabase":3},{"id":4,"title":5,"body":6,"description":271,"extension":272,"group":273,"meta":274,"navigation":275,"order":276,"path":277,"section":278,"seo":279,"source":280,"stem":281,"version":282,"__hash__":283},"docs\u002Fdocs\u002Fmain\u002Fdatabase.md","Databases and migrations",{"type":7,"value":8,"toc":264},"minimark",[9,14,30,34,41,45,68,71,75,78,127,130,190,193,229,240,244,260],[10,11,13],"h2",{"id":12},"configure-a-database-resource","Configure a database resource",[15,16,17,21,22,25,26,29],"p",{},[18,19,20],"code",{},"orm.New(orm.Options{Dialect:\"sqlite\", DSNEnv:\"DATABASE_URL\"})"," constructs a resource without pinging. Register it with ",[18,23,24],{},"Registrar.Manage","; startup opens\u002Fpings and shutdown closes its SQL pool. ",[18,27,28],{},"orm.Open(ctx, options)"," opens immediately for explicit tools\u002Ftests. Never log DSNs. Driver errors from opening\u002Fpinging are redacted. Pool limits, idle time and lifetime are configurable. The initial verified dialect is real file-backed SQLite using ncruces\u002Fgormlite (CGO-free); PostgreSQL uses GORM's official driver.",[10,31,33],{"id":32},"keep-repositories-at-the-boundary","Keep repositories at the boundary",[15,35,36,37,40],{},"Services define local repository interfaces; GORM adapters map values and not-found\u002Funique errors. ",[18,38,39],{},"orm.Transaction"," accepts a GORM callback only at the adapter boundary. A service needing atomic multi-write behavior should define a small local transaction callback interface implemented by that adapter.",[10,42,44],{"id":43},"apply-immutable-migrations","Apply immutable migrations",[15,46,47,48,51,52,55,56,59,60,63,64,67],{},"Migrations are immutable UTF-8 SQL files named ",[18,49,50],{},"000001_description.up.sql",". Use ",[18,53,54],{},"migration.New(pool, dialect, files)"," with an embedded or directory ",[18,57,58],{},"fs.FS",", then explicitly call ",[18,61,62],{},"Up(ctx)"," or ",[18,65,66],{},"Status(ctx)",". SQL must be transaction-compatible; do not put BEGIN\u002FCOMMIT, nontransactional DDL or connection-level PRAGMAs inside a migration. The runner uses one transaction for the full pending batch, a version\u002Fchecksum history table, SQLite BEGIN IMMEDIATE via serializable isolation, and PostgreSQL transaction advisory locks. Concurrent runners cannot apply the same migration twice. Changes to applied contents\u002Fnames, missing versions and out-of-order history fail clearly. Repeating an unchanged migration set is a no-op. Status initializes an empty history table if needed.",[15,69,70],{},"No AutoMigrate or implicit application-start schema changes. Down migrations are deliberately absent from the example because dropping persisted users is destructive. Forward corrections use new versions.",[10,72,74],{"id":73},"add-persistence-to-your-application","Add persistence to your application",[15,76,77],{},"From your generated application root:",[79,80,85],"pre",{"className":81,"code":82,"language":83,"meta":84,"style":84},"language-sh shiki shiki-themes light-plus light-plus dark-plus","go tool gonex create module messages --db\ngo mod tidy\n","sh","",[18,86,87,116],{"__ignoreMap":84},[88,89,92,96,100,103,106,109,112],"span",{"class":90,"line":91},"line",1,[88,93,95],{"class":94},"swoLU","go",[88,97,99],{"class":98},"sFD8J"," tool",[88,101,102],{"class":98}," gonex",[88,104,105],{"class":98}," create",[88,107,108],{"class":98}," module",[88,110,111],{"class":98}," messages",[88,113,115],{"class":114},"stxUP"," --db\n",[88,117,119,121,124],{"class":90,"line":118},2,[88,120,95],{"class":94},[88,122,123],{"class":98}," mod",[88,125,126],{"class":98}," tidy\n",[15,128,129],{},"Configure SQLite in the process environment. POSIX shell:",[79,131,133],{"className":81,"code":132,"language":83,"meta":84,"style":84},"export DATABASE_DIALECT=sqlite\nexport DATABASE_URL='file:app.db?_pragma=busy_timeout(5000)'\ngo tool gonex db migrate\ngo tool gonex run\n",[18,134,135,151,163,178],{"__ignoreMap":84},[88,136,137,140,144,148],{"class":90,"line":91},[88,138,139],{"class":114},"export",[88,141,143],{"class":142},"sswaR"," DATABASE_DIALECT",[88,145,147],{"class":146},"s_Yst","=",[88,149,150],{"class":142},"sqlite\n",[88,152,153,155,158,160],{"class":90,"line":118},[88,154,139],{"class":114},[88,156,157],{"class":142}," DATABASE_URL",[88,159,147],{"class":146},[88,161,162],{"class":98},"'file:app.db?_pragma=busy_timeout(5000)'\n",[88,164,166,168,170,172,175],{"class":90,"line":165},3,[88,167,95],{"class":94},[88,169,99],{"class":98},[88,171,102],{"class":98},[88,173,174],{"class":98}," db",[88,176,177],{"class":98}," migrate\n",[88,179,181,183,185,187],{"class":90,"line":180},4,[88,182,95],{"class":94},[88,184,99],{"class":98},[88,186,102],{"class":98},[88,188,189],{"class":98}," run\n",[15,191,192],{},"PowerShell:",[79,194,198],{"className":195,"code":196,"language":197,"meta":84,"style":84},"language-powershell shiki shiki-themes light-plus light-plus dark-plus","$env:DATABASE_DIALECT='sqlite'\n$env:DATABASE_URL='file:app.db?_pragma=busy_timeout(5000)'\ngo tool gonex db migrate\ngo tool gonex run\n","powershell",[18,199,200,210,219,224],{"__ignoreMap":84},[88,201,202,205,207],{"class":90,"line":91},[88,203,204],{"class":142},"$env:DATABASE_DIALECT",[88,206,147],{"class":146},[88,208,209],{"class":98},"'sqlite'\n",[88,211,212,215,217],{"class":90,"line":118},[88,213,214],{"class":142},"$env:DATABASE_URL",[88,216,147],{"class":146},[88,218,162],{"class":98},[88,220,221],{"class":90,"line":165},[88,222,223],{"class":146},"go tool gonex db migrate\n",[88,225,226],{"class":90,"line":180},[88,227,228],{"class":146},"go tool gonex run\n",[15,230,231,232,235,236,239],{},"The starter ",[18,233,234],{},"GET \u002Fmessages"," reads its seeded message from the database. Extend its handwritten service, repository, schemas and routes for your domain; ",[18,237,238],{},"--db"," does not generate a complete model CRUD API. Serving never runs migrations automatically. No framework checkout or automatic .env loading is required.",[10,241,243],{"id":242},"verify-database-behavior","Verify database behavior",[15,245,246,247,250,251,254,255,259],{},"Framework maintainers run ",[18,248,249],{},"go test .\u002F..."," in the framework repository to test file-backed SQLite CRUD, transactions, migration rollback\u002Fchecksums\u002Fconcurrency and lifecycle cleanup. PostgreSQL integration is explicitly skipped unless ",[18,252,253],{},"GONEX_TEST_POSTGRES_DSN"," identifies an ",[256,257,258],"strong",{},"empty disposable test database","; it is never inferred from production DATABASE_URL. PostgreSQL credentials and deployment-specific behavior require that integration environment.",[261,262,263],"style",{},"html pre.shiki code .swoLU, html code.shiki .swoLU{--shiki-light:#795E26;--shiki-default:#795E26;--shiki-dark:#DCDCAA}html pre.shiki code .sFD8J, html code.shiki .sFD8J{--shiki-light:#A31515;--shiki-default:#A31515;--shiki-dark:#CE9178}html pre.shiki code .stxUP, html code.shiki .stxUP{--shiki-light:#0000FF;--shiki-default:#0000FF;--shiki-dark:#569CD6}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 .sswaR, html code.shiki .sswaR{--shiki-light:#001080;--shiki-default:#001080;--shiki-dark:#9CDCFE}html pre.shiki code .s_Yst, html code.shiki .s_Yst{--shiki-light:#000000;--shiki-default:#000000;--shiki-dark:#D4D4D4}",{"title":84,"searchDepth":118,"depth":118,"links":265},[266,267,268,269,270],{"id":12,"depth":118,"text":13},{"id":32,"depth":118,"text":33},{"id":43,"depth":118,"text":44},{"id":73,"depth":118,"text":74},{"id":242,"depth":118,"text":243},"Use optional GORM adapters with SQLite or PostgreSQL and explicit, checksum-verified SQL migrations.","md","APPLICATION DESIGN",{},true,110,"\u002Fdocs\u002Fmain\u002Fdatabase","build",{"title":5,"description":271},"database-migrations.md","docs\u002Fmain\u002Fdatabase","main","RQNB0fqlrd0UTbxCYeVjLnLF5JkKXcpKN6dwnjc3pwQ",1792521640497]