[{"data":1,"prerenderedAt":1429},["ShallowReactive",2],{"navigation_docs_en":3,"-en-envconf-recipes":448,"-en-envconf-recipes-surround":1424},[4,45,120,157,173,203,233,259,271,287,307,326,339,356,373,386,398,425],{"title":5,"icon":6,"path":7,"stem":8,"children":9,"page":44},"Getting Started","i-lucide-rocket","\u002Fen\u002Fgetting-started","en\u002F01.getting-started",[10,15,20,25,30,35,40],{"title":11,"path":12,"stem":13,"icon":14},"Introduction","\u002Fen\u002Fgetting-started\u002Fintroduction","en\u002F01.getting-started\u002F1.introduction","i-lucide-house",{"title":16,"path":17,"stem":18,"icon":19},"Installation","\u002Fen\u002Fgetting-started\u002Finstallation","en\u002F01.getting-started\u002F2.installation","i-lucide-download",{"title":21,"path":22,"stem":23,"icon":24},"Your first module","\u002Fen\u002Fgetting-started\u002Ffirst-module","en\u002F01.getting-started\u002F3.first-module","i-lucide-package-plus",{"title":26,"path":27,"stem":28,"icon":29},"Project structure","\u002Fen\u002Fgetting-started\u002Fproject-structure","en\u002F01.getting-started\u002F4.project-structure","i-lucide-folder-tree",{"title":31,"path":32,"stem":33,"icon":34},"The shop sample application","\u002Fen\u002Fgetting-started\u002Fsample-app","en\u002F01.getting-started\u002F5.sample-app","i-lucide-shopping-cart",{"title":36,"path":37,"stem":38,"icon":39},"Coming from Laravel","\u002Fen\u002Fgetting-started\u002Fcoming-from-laravel","en\u002F01.getting-started\u002F6.coming-from-laravel","i-lucide-arrow-right-left",{"title":41,"path":42,"stem":43,"icon":39},"Coming from Symfony","\u002Fen\u002Fgetting-started\u002Fcoming-from-symfony","en\u002F01.getting-started\u002F7.coming-from-symfony",false,{"title":46,"icon":47,"path":48,"stem":49,"children":50,"page":44},"CLI Reference","i-lucide-terminal","\u002Fen\u002Fcli","en\u002F02.cli",[51,55,60,65,70,75,80,85,90,95,100,105,110,115],{"title":52,"path":53,"stem":54,"icon":47},"Overview","\u002Fen\u002Fcli\u002Foverview","en\u002F02.cli\u002F1.overview",{"title":56,"path":57,"stem":58,"icon":59},"add compose \u002F add docker","\u002Fen\u002Fcli\u002Fadd-compose","en\u002F02.cli\u002F10.add-compose","i-lucide-container",{"title":61,"path":62,"stem":63,"icon":64},"add mail","\u002Fen\u002Fcli\u002Fadd-mail","en\u002F02.cli\u002F11.add-mail","i-lucide-mail-plus",{"title":66,"path":67,"stem":68,"icon":69},"add notification","\u002Fen\u002Fcli\u002Fadd-notification","en\u002F02.cli\u002F12.add-notification","i-lucide-bell-plus",{"title":71,"path":72,"stem":73,"icon":74},"add realtime","\u002Fen\u002Fcli\u002Fadd-realtime","en\u002F02.cli\u002F13.add-realtime","i-lucide-radio-tower",{"title":76,"path":77,"stem":78,"icon":79},"add seeder","\u002Fen\u002Fcli\u002Fadd-seeder","en\u002F02.cli\u002F14.add-seeder","i-lucide-sprout",{"title":81,"path":82,"stem":83,"icon":84},"new project","\u002Fen\u002Fcli\u002Fnew-project","en\u002F02.cli\u002F2.new-project","i-lucide-folder-plus",{"title":86,"path":87,"stem":88,"icon":89},"new module","\u002Fen\u002Fcli\u002Fnew-module","en\u002F02.cli\u002F3.new-module","i-lucide-blocks",{"title":91,"path":92,"stem":93,"icon":94},"add surface","\u002Fen\u002Fcli\u002Fadd-surface","en\u002F02.cli\u002F4.add-surface","i-lucide-layers-2",{"title":96,"path":97,"stem":98,"icon":99},"add domain","\u002Fen\u002Fcli\u002Fadd-domain","en\u002F02.cli\u002F5.add-domain","i-lucide-box",{"title":101,"path":102,"stem":103,"icon":104},"add handler","\u002Fen\u002Fcli\u002Fadd-handler","en\u002F02.cli\u002F6.add-handler","i-lucide-webhook",{"title":106,"path":107,"stem":108,"icon":109},"new migration","\u002Fen\u002Fcli\u002Fnew-migration","en\u002F02.cli\u002F7.new-migration","i-lucide-file-plus",{"title":111,"path":112,"stem":113,"icon":114},"worker generators","\u002Fen\u002Fcli\u002Fworker-generators","en\u002F02.cli\u002F8.worker-generators","i-lucide-cog",{"title":116,"path":117,"stem":118,"icon":119},"add db","\u002Fen\u002Fcli\u002Fadd-db","en\u002F02.cli\u002F9.add-db","i-lucide-database-zap",{"title":121,"icon":99,"path":122,"stem":123,"children":124,"page":44},"Framework","\u002Fen\u002Fframework","en\u002F03.framework",[125,128,133,138,142,147,152],{"title":52,"path":126,"stem":127,"icon":99},"\u002Fen\u002Fframework\u002Foverview","en\u002F03.framework\u002F1.overview",{"title":129,"path":130,"stem":131,"icon":132},"Application lifecycle","\u002Fen\u002Fframework\u002Fapp","en\u002F03.framework\u002F2.app","i-lucide-power",{"title":134,"path":135,"stem":136,"icon":137},"Server","\u002Fen\u002Fframework\u002Fserver","en\u002F03.framework\u002F3.server","i-lucide-server",{"title":139,"path":140,"stem":141,"icon":114},"Worker","\u002Fen\u002Fframework\u002Fworker","en\u002F03.framework\u002F4.worker",{"title":143,"path":144,"stem":145,"icon":146},"Realtime","\u002Fen\u002Fframework\u002Frealtime","en\u002F03.framework\u002F5.realtime","i-lucide-radio",{"title":148,"path":149,"stem":150,"icon":151},"Migrations","\u002Fen\u002Fframework\u002Fmigrations","en\u002F03.framework\u002F6.migrations","i-lucide-file-stack",{"title":153,"path":154,"stem":155,"icon":156},"Social login","\u002Fen\u002Fframework\u002Fsocial-login","en\u002F03.framework\u002F7.social-login","i-lucide-log-in",{"title":158,"icon":159,"path":160,"stem":161,"children":162,"page":44},"Reference","i-lucide-book-open","\u002Fen\u002Freference","en\u002F04.reference",[163,168],{"title":164,"path":165,"stem":166,"icon":167},"Configuration","\u002Fen\u002Freference\u002Fconfiguration","en\u002F04.reference\u002F1.configuration","i-lucide-settings",{"title":169,"path":170,"stem":171,"icon":172},"External dependencies","\u002Fen\u002Freference\u002Fdependencies","en\u002F04.reference\u002F2.dependencies","i-lucide-package",{"title":174,"icon":175,"path":176,"stem":177,"children":178,"page":44},"Concepts","i-lucide-lightbulb","\u002Fen\u002Fconcepts","en\u002F05.concepts",[179,184,189,193,198],{"title":180,"path":181,"stem":182,"icon":183},"Architecture","\u002Fen\u002Fconcepts\u002Farchitecture","en\u002F05.concepts\u002F1.architecture","i-lucide-layers",{"title":185,"path":186,"stem":187,"icon":188},"Error model","\u002Fen\u002Fconcepts\u002Ferror-model","en\u002F05.concepts\u002F2.error-model","i-lucide-shield-alert",{"title":164,"path":190,"stem":191,"icon":192},"\u002Fen\u002Fconcepts\u002Fconfiguration","en\u002F05.concepts\u002F3.configuration","i-lucide-settings-2",{"title":194,"path":195,"stem":196,"icon":197},"Codegen pipeline","\u002Fen\u002Fconcepts\u002Fcodegen-pipeline","en\u002F05.concepts\u002F4.codegen-pipeline","i-lucide-file-json",{"title":199,"path":200,"stem":201,"icon":202},"Design patterns","\u002Fen\u002Fconcepts\u002Fdesign-patterns","en\u002F05.concepts\u002F5.design-patterns","i-lucide-puzzle",{"title":204,"icon":205,"path":206,"stem":207,"children":208,"page":44},"auth","i-lucide-shield-check","\u002Fen\u002Fauth","en\u002F06.auth",[209,214,219,224,229],{"title":210,"path":211,"stem":212,"icon":213},"Authentication","\u002Fen\u002Fauth\u002Foverview","en\u002F06.auth\u002F1.overview","i-lucide-key-round",{"title":215,"path":216,"stem":217,"icon":218},"RBAC","\u002Fen\u002Fauth\u002Frbac","en\u002F06.auth\u002F2.rbac","i-lucide-users",{"title":220,"path":221,"stem":222,"icon":223},"Policies","\u002Fen\u002Fauth\u002Fpolicy","en\u002F06.auth\u002F3.policy","i-lucide-gavel",{"title":225,"path":226,"stem":227,"icon":228},"Using auth standalone","\u002Fen\u002Fauth\u002Fstandalone","en\u002F06.auth\u002F4.standalone","i-lucide-plug",{"title":230,"path":231,"stem":232,"icon":156},"Social login with goth, standalone","\u002Fen\u002Fauth\u002Fsocial-standalone","en\u002F06.auth\u002F5.social-standalone",{"title":234,"icon":235,"path":236,"stem":237,"children":238,"page":44},"dbx","i-lucide-database","\u002Fen\u002Fdbx","en\u002F07.dbx",[239,242,246,250,255],{"title":52,"path":240,"stem":241,"icon":235},"\u002Fen\u002Fdbx\u002Foverview","en\u002F07.dbx\u002F1.overview",{"title":243,"path":244,"stem":245,"icon":228},"pgx","\u002Fen\u002Fdbx\u002Fpg","en\u002F07.dbx\u002F2.pg",{"title":247,"path":248,"stem":249,"icon":183},"bun","\u002Fen\u002Fdbx\u002Fbunx","en\u002F07.dbx\u002F3.bunx",{"title":251,"path":252,"stem":253,"icon":254},"Transactions","\u002Fen\u002Fdbx\u002Ftransactions","en\u002F07.dbx\u002F4.transactions","i-lucide-git-merge",{"title":256,"path":257,"stem":258,"icon":79},"Seeders","\u002Fen\u002Fdbx\u002Fseed","en\u002F07.dbx\u002F5.seed",{"title":260,"icon":192,"path":261,"stem":262,"children":263,"page":44},"envconf","\u002Fen\u002Fenvconf","en\u002F08.envconf",[264,267],{"title":52,"path":265,"stem":266,"icon":192},"\u002Fen\u002Fenvconf\u002Foverview","en\u002F08.envconf\u002F1.overview",{"title":268,"path":269,"stem":270,"icon":192},"Recipes","\u002Fen\u002Fenvconf\u002Frecipes","en\u002F08.envconf\u002F2.recipes",{"title":272,"icon":188,"path":273,"stem":274,"children":275,"page":44},"errs","\u002Fen\u002Ferrs","en\u002F09.errs",[276,279,283],{"title":52,"path":277,"stem":278,"icon":188},"\u002Fen\u002Ferrs\u002Foverview","en\u002F09.errs\u002F1.overview",{"title":280,"path":281,"stem":282,"icon":188},"API","\u002Fen\u002Ferrs\u002Fapi","en\u002F09.errs\u002F2.api",{"title":284,"path":285,"stem":286,"icon":188},"Integration","\u002Fen\u002Ferrs\u002Fintegration","en\u002F09.errs\u002F3.integration",{"title":288,"icon":289,"path":290,"stem":291,"children":292,"page":44},"events","i-lucide-workflow","\u002Fen\u002Fevents","en\u002F10.events",[293,297,302],{"title":294,"path":295,"stem":296,"icon":146},"Events","\u002Fen\u002Fevents\u002Foverview","en\u002F10.events\u002F1.overview",{"title":298,"path":299,"stem":300,"icon":301},"Outbox","\u002Fen\u002Fevents\u002Foutbox","en\u002F10.events\u002F2.outbox","i-lucide-inbox",{"title":303,"path":304,"stem":305,"icon":306},"Scheduling","\u002Fen\u002Fevents\u002Fscheduler","en\u002F10.events\u002F3.scheduler","i-lucide-calendar-clock",{"title":308,"icon":309,"path":310,"stem":311,"children":312,"page":44},"httperr","i-lucide-globe","\u002Fen\u002Fhttperr","en\u002F11.httperr",[313,316,321],{"title":52,"path":314,"stem":315,"icon":309},"\u002Fen\u002Fhttperr\u002Foverview","en\u002F11.httperr\u002F1.overview",{"title":317,"path":318,"stem":319,"icon":320},"Error responses","\u002Fen\u002Fhttperr\u002Ferror-responses","en\u002F11.httperr\u002F2.error-responses","i-lucide-octagon-alert",{"title":322,"path":323,"stem":324,"icon":325},"Validation","\u002Fen\u002Fhttperr\u002Fvalidation","en\u002F11.httperr\u002F3.validation","i-lucide-badge-check",{"title":327,"icon":328,"path":329,"stem":330,"children":331,"page":44},"logx","i-lucide-scroll-text","\u002Fen\u002Flogx","en\u002F12.logx",[332,335],{"title":52,"path":333,"stem":334,"icon":328},"\u002Fen\u002Flogx\u002Foverview","en\u002F12.logx\u002F1.overview",{"title":336,"path":337,"stem":338,"icon":47},"Monolog formatter","\u002Fen\u002Flogx\u002Fmonolog","en\u002F12.logx\u002F2.monolog",{"title":340,"icon":341,"path":342,"stem":343,"children":344,"page":44},"mail","i-lucide-mail","\u002Fen\u002Fmail","en\u002F13.mail",[345,348,352],{"title":52,"path":346,"stem":347,"icon":341},"\u002Fen\u002Fmail\u002Foverview","en\u002F13.mail\u002F1.overview",{"title":349,"path":350,"stem":351,"icon":341},"SMTP","\u002Fen\u002Fmail\u002Fsmtp","en\u002F13.mail\u002F2.smtp",{"title":353,"path":354,"stem":355,"icon":341},"MJML","\u002Fen\u002Fmail\u002Fmjml","en\u002F13.mail\u002F3.mjml",{"title":357,"icon":358,"path":359,"stem":360,"children":361,"page":44},"notify","i-lucide-bell","\u002Fen\u002Fnotify","en\u002F14.notify",[362,365,369],{"title":52,"path":363,"stem":364,"icon":358},"\u002Fen\u002Fnotify\u002Foverview","en\u002F14.notify\u002F1.overview",{"title":366,"path":367,"stem":368,"icon":358},"Database channel","\u002Fen\u002Fnotify\u002Fdatabase","en\u002F14.notify\u002F2.database",{"title":370,"path":371,"stem":372,"icon":358},"Broadcast channel","\u002Fen\u002Fnotify\u002Fbroadcast","en\u002F14.notify\u002F3.broadcast",{"title":374,"icon":375,"path":376,"stem":377,"children":378,"page":44},"paginate","i-lucide-list-ordered","\u002Fen\u002Fpaginate","en\u002F15.paginate",[379,382],{"title":52,"path":380,"stem":381,"icon":375},"\u002Fen\u002Fpaginate\u002Foverview","en\u002F15.paginate\u002F1.overview",{"title":383,"path":384,"stem":385,"icon":39},"Cursor pagination","\u002Fen\u002Fpaginate\u002Fcursor","en\u002F15.paginate\u002F2.cursor",{"title":387,"icon":183,"path":388,"stem":389,"children":390,"page":44},"queue","\u002Fen\u002Fqueue","en\u002F16.queue",[391,394],{"title":52,"path":392,"stem":393,"icon":375},"\u002Fen\u002Fqueue\u002Foverview","en\u002F16.queue\u002F1.overview",{"title":395,"path":396,"stem":397,"icon":183},"Tasks","\u002Fen\u002Fqueue\u002Ftasks","en\u002F16.queue\u002F2.tasks",{"title":399,"icon":400,"path":401,"stem":402,"children":403,"page":44},"storage","i-lucide-hard-drive","\u002Fen\u002Fstorage","en\u002F17.storage",[404,407,411,415,420],{"title":52,"path":405,"stem":406,"icon":400},"\u002Fen\u002Fstorage\u002Foverview","en\u002F17.storage\u002F1.overview",{"title":408,"path":409,"stem":410,"icon":400},"Disk API","\u002Fen\u002Fstorage\u002Fdisk-api","en\u002F17.storage\u002F2.disk-api",{"title":412,"path":413,"stem":414,"icon":400},"Memory and local disk","\u002Fen\u002Fstorage\u002Flocal","en\u002F17.storage\u002F3.local",{"title":416,"path":417,"stem":418,"icon":419},"S3","\u002Fen\u002Fstorage\u002Fs3","en\u002F17.storage\u002F4.s3","i-lucide-cloud",{"title":421,"path":422,"stem":423,"icon":424},"Testing","\u002Fen\u002Fstorage\u002Ftesting","en\u002F17.storage\u002F5.testing","i-lucide-flask-conical",{"title":426,"icon":427,"path":428,"stem":429,"children":430,"page":44},"telemetry","i-lucide-activity","\u002Fen\u002Ftelemetry","en\u002F18.telemetry",[431,434,438,443],{"title":52,"path":432,"stem":433,"icon":427},"\u002Fen\u002Ftelemetry\u002Foverview","en\u002F18.telemetry\u002F1.overview",{"title":435,"path":436,"stem":437,"icon":328},"Logging","\u002Fen\u002Ftelemetry\u002Flogging","en\u002F18.telemetry\u002F2.logging",{"title":439,"path":440,"stem":441,"icon":442},"OpenTelemetry","\u002Fen\u002Ftelemetry\u002Fopentelemetry","en\u002F18.telemetry\u002F3.opentelemetry","i-lucide-radar",{"title":444,"path":445,"stem":446,"icon":447},"Sentry","\u002Fen\u002Ftelemetry\u002Fsentry","en\u002F18.telemetry\u002F4.sentry","i-lucide-bug",{"id":449,"title":268,"body":450,"description":1417,"extension":1418,"links":1419,"meta":1420,"navigation":1421,"path":269,"seo":1422,"stem":270,"__hash__":1423},"docs_en\u002Fen\u002F08.envconf\u002F2.recipes.md",{"type":451,"value":452,"toc":1410},"minimark",[453,470,475,489,675,710,782,786,799,944,983,996,1000,1012,1328,1346,1350,1372,1376,1406],[454,455,456,457,461,462,465,466,469],"p",{},"Three patterns cover almost everything a real project needs beyond the basic ",[458,459,460],"code",{},"Load","\u002F",[458,463,464],{},"MustLoad"," call on the ",[467,468,52],"a",{"href":265}," page: composing a root config out of several modules' configs, loading the same shape more than once under different prefixes, and testing code that reads configuration.",[471,472,474],"h2",{"id":473},"composing-a-root-config-from-module-configs","Composing a root Config from module configs",[454,476,477,478,481,482,484,485,488],{},"Every gp-system module that needs configuration exports its own ",[458,479,480],{},"Config"," struct, tagged with its own field names, with no opinion on what (if anything) prefixes them. A generated gpsystem project composes those structs into one application-wide ",[458,483,480],{}," by nesting them as fields and choosing a prefix per field with ",[458,486,487],{},"envPrefix",":",[490,491,497],"pre",{"className":492,"code":493,"filename":494,"language":495,"meta":496,"style":496},"language-go shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","package config\n\nimport (\n    \"github.com\u002Fgp-system\u002Fdbx\"\n    \"github.com\u002Fgp-system\u002Fevents\u002Foutbox\"\n    \"github.com\u002Fgp-system\u002Fframework\u002Fserver\"\n    \"github.com\u002Fgp-system\u002Fframework\u002Fworker\"\n)\n\ntype Config struct {\n    Server server.Config\n    DB     dbx.Config    `envPrefix:\"DB_\"`\n    Worker worker.Config\n    Outbox outbox.Config `envPrefix:\"OUTBOX_\"`\n}\n","internal\u002Fplatform\u002Fconfig\u002Fconfig.go","go","",[458,498,499,512,519,529,541,551,561,571,577,582,597,613,635,648,669],{"__ignoreMap":496},[500,501,504,508],"span",{"class":502,"line":503},"line",1,[500,505,507],{"class":506},"sMK4o","package",[500,509,511],{"class":510},"sBMFI"," config\n",[500,513,515],{"class":502,"line":514},2,[500,516,518],{"emptyLinePlaceholder":517},true,"\n",[500,520,522,526],{"class":502,"line":521},3,[500,523,525],{"class":524},"s7zQu","import",[500,527,528],{"class":506}," (\n",[500,530,532,535,538],{"class":502,"line":531},4,[500,533,534],{"class":506},"    \"",[500,536,537],{"class":510},"github.com\u002Fgp-system\u002Fdbx",[500,539,540],{"class":506},"\"\n",[500,542,544,546,549],{"class":502,"line":543},5,[500,545,534],{"class":506},[500,547,548],{"class":510},"github.com\u002Fgp-system\u002Fevents\u002Foutbox",[500,550,540],{"class":506},[500,552,554,556,559],{"class":502,"line":553},6,[500,555,534],{"class":506},[500,557,558],{"class":510},"github.com\u002Fgp-system\u002Fframework\u002Fserver",[500,560,540],{"class":506},[500,562,564,566,569],{"class":502,"line":563},7,[500,565,534],{"class":506},[500,567,568],{"class":510},"github.com\u002Fgp-system\u002Fframework\u002Fworker",[500,570,540],{"class":506},[500,572,574],{"class":502,"line":573},8,[500,575,576],{"class":506},")\n",[500,578,580],{"class":502,"line":579},9,[500,581,518],{"emptyLinePlaceholder":517},[500,583,585,588,591,594],{"class":502,"line":584},10,[500,586,587],{"class":506},"type",[500,589,590],{"class":510}," Config",[500,592,593],{"class":506}," struct",[500,595,596],{"class":506}," {\n",[500,598,600,604,607,610],{"class":502,"line":599},11,[500,601,603],{"class":602},"sTEyZ","    Server ",[500,605,606],{"class":510},"server",[500,608,609],{"class":506},".",[500,611,612],{"class":510},"Config\n",[500,614,616,619,621,623,625,628,632],{"class":502,"line":615},12,[500,617,618],{"class":602},"    DB     ",[500,620,234],{"class":510},[500,622,609],{"class":506},[500,624,480],{"class":510},[500,626,627],{"class":506},"    `",[500,629,631],{"class":630},"sfazB","envPrefix:\"DB_\"",[500,633,634],{"class":506},"`\n",[500,636,638,641,644,646],{"class":502,"line":637},13,[500,639,640],{"class":602},"    Worker ",[500,642,643],{"class":510},"worker",[500,645,609],{"class":506},[500,647,612],{"class":510},[500,649,651,654,657,659,661,664,667],{"class":502,"line":650},14,[500,652,653],{"class":602},"    Outbox ",[500,655,656],{"class":510},"outbox",[500,658,609],{"class":506},[500,660,480],{"class":510},[500,662,663],{"class":506}," `",[500,665,666],{"class":630},"envPrefix:\"OUTBOX_\"",[500,668,634],{"class":506},[500,670,672],{"class":502,"line":671},15,[500,673,674],{"class":506},"}\n",[490,676,679],{"className":492,"code":677,"filename":678,"language":495,"meta":496,"style":496},"cfg := envconf.MustLoad[config.Config]()\n","cmd\u002Fshop\u002Fmain.go",[458,680,681],{"__ignoreMap":496},[500,682,683,686,689,692,694,697,700,703,705,707],{"class":502,"line":503},[500,684,685],{"class":602},"cfg ",[500,687,688],{"class":506},":=",[500,690,691],{"class":602}," envconf",[500,693,609],{"class":506},[500,695,464],{"class":696},"s2Zo4",[500,698,699],{"class":506},"[",[500,701,702],{"class":510},"config",[500,704,609],{"class":506},[500,706,480],{"class":510},[500,708,709],{"class":506},"]()\n",[454,711,712,713,716,717,719,720,723,724,728,729,732,733,736,737,736,740,743,744,746,747,736,750,736,753,756,757,760,761,763,764,767,768,736,771,736,774,777,778,781],{},"One ",[458,714,715],{},"envconf.Load[AppConfig]()"," (or ",[458,718,464],{},") call at the top of ",[458,721,722],{},"main()"," is all a process needs: every module's settings arrive fully typed in one struct, with no further parsing anywhere else in the codebase. The rule is: ",[725,726,727],"strong",{},"a module names its own fields, the embedder decides the prefix."," ",[458,730,731],{},"dbx.Config","'s own tags are ",[458,734,735],{},"HOST",", ",[458,738,739],{},"PORT",[458,741,742],{},"USER",", ...; nested under ",[458,745,631],{}," they become ",[458,748,749],{},"DB_HOST",[458,751,752],{},"DB_PORT",[458,754,755],{},"DB_USER",". A struct embedded without a prefix (like ",[458,758,759],{},"server.Config"," above) reads its variables under their own, unprefixed names. Nesting can go arbitrarily deep: ",[458,762,759],{}," itself embeds a ",[458,765,766],{},"telemetry.Config",", unprefixed, because its variables (",[458,769,770],{},"OTEL_SERVICE_NAME",[458,772,773],{},"SENTRY_DSN",[458,775,776],{},"LOG_LEVEL",") are already industry-standard names that every OTel\u002FSentry-aware tool expects as-is. See ",[467,779,164],{"href":780},"\u002Fen\u002Fconcepts\u002Fconfiguration#the-env-prefix-conventions"," for the full prefix table gpsystem's own modules settle into.",[471,783,785],{"id":784},"prefixed-multi-instance-loads","Prefixed multi-instance loads",[454,787,788,790,791,794,795,798],{},[458,789,487],{}," on a nested field only helps when the struct is embedded once. When a process genuinely needs ",[725,792,793],{},"two independent instances"," of the same config shape (two Valkey connections: one for caching, one for the queue), ",[458,796,797],{},"LoadPrefixed"," loads the same type twice, under two different top-level prefixes, with no struct nesting required:",[490,800,802],{"className":492,"code":801,"language":495,"meta":496,"style":496},"type ValkeyConfig struct {\n    Addr     string `env:\"ADDR,required\"`\n    Password string `env:\"PASSWORD\"`\n    DB       int    `env:\"DB\" envDefault:\"0\"`\n}\n\ncache, err := envconf.LoadPrefixed[ValkeyConfig](\"CACHE_VALKEY_\")  \u002F\u002F CACHE_VALKEY_ADDR, CACHE_VALKEY_PASSWORD, CACHE_VALKEY_DB\nqueue, err := envconf.LoadPrefixed[ValkeyConfig](\"QUEUE_VALKEY_\")  \u002F\u002F QUEUE_VALKEY_ADDR, QUEUE_VALKEY_PASSWORD, QUEUE_VALKEY_DB\n",[458,803,804,815,831,845,860,864,868,910],{"__ignoreMap":496},[500,805,806,808,811,813],{"class":502,"line":503},[500,807,587],{"class":506},[500,809,810],{"class":510}," ValkeyConfig",[500,812,593],{"class":506},[500,814,596],{"class":506},[500,816,817,820,824,826,829],{"class":502,"line":514},[500,818,819],{"class":602},"    Addr     ",[500,821,823],{"class":822},"spNyl","string",[500,825,663],{"class":506},[500,827,828],{"class":630},"env:\"ADDR,required\"",[500,830,634],{"class":506},[500,832,833,836,838,840,843],{"class":502,"line":521},[500,834,835],{"class":602},"    Password ",[500,837,823],{"class":822},[500,839,663],{"class":506},[500,841,842],{"class":630},"env:\"PASSWORD\"",[500,844,634],{"class":506},[500,846,847,850,853,855,858],{"class":502,"line":531},[500,848,849],{"class":602},"    DB       ",[500,851,852],{"class":822},"int",[500,854,627],{"class":506},[500,856,857],{"class":630},"env:\"DB\" envDefault:\"0\"",[500,859,634],{"class":506},[500,861,862],{"class":502,"line":543},[500,863,674],{"class":506},[500,865,866],{"class":502,"line":553},[500,867,518],{"emptyLinePlaceholder":517},[500,869,870,873,876,879,881,883,885,887,889,892,895,898,901,903,906],{"class":502,"line":563},[500,871,872],{"class":602},"cache",[500,874,875],{"class":506},",",[500,877,878],{"class":602}," err ",[500,880,688],{"class":506},[500,882,691],{"class":602},[500,884,609],{"class":506},[500,886,797],{"class":696},[500,888,699],{"class":506},[500,890,891],{"class":510},"ValkeyConfig",[500,893,894],{"class":506},"](",[500,896,897],{"class":506},"\"",[500,899,900],{"class":630},"CACHE_VALKEY_",[500,902,897],{"class":506},[500,904,905],{"class":506},")",[500,907,909],{"class":908},"sHwdD","  \u002F\u002F CACHE_VALKEY_ADDR, CACHE_VALKEY_PASSWORD, CACHE_VALKEY_DB\n",[500,911,912,914,916,918,920,922,924,926,928,930,932,934,937,939,941],{"class":502,"line":573},[500,913,387],{"class":602},[500,915,875],{"class":506},[500,917,878],{"class":602},[500,919,688],{"class":506},[500,921,691],{"class":602},[500,923,609],{"class":506},[500,925,797],{"class":696},[500,927,699],{"class":506},[500,929,891],{"class":510},[500,931,894],{"class":506},[500,933,897],{"class":506},[500,935,936],{"class":630},"QUEUE_VALKEY_",[500,938,897],{"class":506},[500,940,905],{"class":506},[500,942,943],{"class":908},"  \u002F\u002F QUEUE_VALKEY_ADDR, QUEUE_VALKEY_PASSWORD, QUEUE_VALKEY_DB\n",[490,945,950],{"className":946,"code":947,"filename":948,"language":949,"meta":496,"style":496},"language-sh shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","CACHE_VALKEY_ADDR=localhost:6379\nQUEUE_VALKEY_ADDR=localhost:6380\nQUEUE_VALKEY_DB=1\n",".env","sh",[458,951,952,963,973],{"__ignoreMap":496},[500,953,954,957,960],{"class":502,"line":503},[500,955,956],{"class":602},"CACHE_VALKEY_ADDR",[500,958,959],{"class":506},"=",[500,961,962],{"class":630},"localhost:6379\n",[500,964,965,968,970],{"class":502,"line":514},[500,966,967],{"class":602},"QUEUE_VALKEY_ADDR",[500,969,959],{"class":506},[500,971,972],{"class":630},"localhost:6380\n",[500,974,975,978,980],{"class":502,"line":521},[500,976,977],{"class":602},"QUEUE_VALKEY_DB",[500,979,959],{"class":506},[500,981,982],{"class":630},"1\n",[454,984,985,986,989,990,992,993,995],{},"Each call is independent: a ",[458,987,988],{},"required"," field missing under one prefix fails only that call, not the other. Reach for ",[458,991,797],{}," specifically when the two instances are genuinely separate connections with independently varying settings; when they'd always share the same values, a single unprefixed ",[458,994,480],{}," field is simpler.",[471,997,999],{"id":998},"testing-with-tsetenv","Testing with t.Setenv",[454,1001,1002,1003,461,1005,1007,1008,1011],{},"Because ",[458,1004,460],{},[458,1006,464],{}," read the real process environment, tests that exercise configuration-dependent code set it directly with ",[458,1009,1010],{},"t.Setenv",", which Go automatically restores after the test (and fails if the test is parallel, which is the right failure: environment variables are process-global state):",[490,1013,1015],{"className":492,"code":1014,"language":495,"meta":496,"style":496},"func TestLoad_defaults(t *testing.T) {\n    t.Setenv(\"DB_HOST\", \"localhost\")\n    t.Setenv(\"DB_USER\", \"test\")\n\n    cfg := envconf.MustLoad[config.Config]()\n\n    if cfg.DB.Host != \"localhost\" {\n        t.Errorf(\"DB.Host = %q, want %q\", cfg.DB.Host, \"localhost\")\n    }\n}\n\nfunc TestLoad_missingRequired(t *testing.T) {\n    \u002F\u002F DB_HOST intentionally not set\n    _, err := envconf.Load[config.Config]()\n    if err == nil {\n        t.Fatal(\"expected an error for missing required DB_HOST\")\n    }\n}\n",[458,1016,1017,1047,1077,1104,1108,1131,1135,1164,1215,1220,1224,1228,1251,1256,1283,1297,1318,1323],{"__ignoreMap":496},[500,1018,1019,1022,1025,1028,1032,1035,1038,1040,1043,1045],{"class":502,"line":503},[500,1020,1021],{"class":506},"func",[500,1023,1024],{"class":696}," TestLoad_defaults",[500,1026,1027],{"class":506},"(",[500,1029,1031],{"class":1030},"sHdIc","t",[500,1033,1034],{"class":506}," *",[500,1036,1037],{"class":510},"testing",[500,1039,609],{"class":506},[500,1041,1042],{"class":510},"T",[500,1044,905],{"class":506},[500,1046,596],{"class":506},[500,1048,1049,1052,1054,1057,1059,1061,1063,1065,1067,1070,1073,1075],{"class":502,"line":514},[500,1050,1051],{"class":602},"    t",[500,1053,609],{"class":506},[500,1055,1056],{"class":696},"Setenv",[500,1058,1027],{"class":506},[500,1060,897],{"class":506},[500,1062,749],{"class":630},[500,1064,897],{"class":506},[500,1066,875],{"class":506},[500,1068,1069],{"class":506}," \"",[500,1071,1072],{"class":630},"localhost",[500,1074,897],{"class":506},[500,1076,576],{"class":506},[500,1078,1079,1081,1083,1085,1087,1089,1091,1093,1095,1097,1100,1102],{"class":502,"line":521},[500,1080,1051],{"class":602},[500,1082,609],{"class":506},[500,1084,1056],{"class":696},[500,1086,1027],{"class":506},[500,1088,897],{"class":506},[500,1090,755],{"class":630},[500,1092,897],{"class":506},[500,1094,875],{"class":506},[500,1096,1069],{"class":506},[500,1098,1099],{"class":630},"test",[500,1101,897],{"class":506},[500,1103,576],{"class":506},[500,1105,1106],{"class":502,"line":531},[500,1107,518],{"emptyLinePlaceholder":517},[500,1109,1110,1113,1115,1117,1119,1121,1123,1125,1127,1129],{"class":502,"line":543},[500,1111,1112],{"class":602},"    cfg ",[500,1114,688],{"class":506},[500,1116,691],{"class":602},[500,1118,609],{"class":506},[500,1120,464],{"class":696},[500,1122,699],{"class":506},[500,1124,702],{"class":510},[500,1126,609],{"class":506},[500,1128,480],{"class":510},[500,1130,709],{"class":506},[500,1132,1133],{"class":502,"line":553},[500,1134,518],{"emptyLinePlaceholder":517},[500,1136,1137,1140,1143,1145,1148,1150,1153,1156,1158,1160,1162],{"class":502,"line":563},[500,1138,1139],{"class":524},"    if",[500,1141,1142],{"class":602}," cfg",[500,1144,609],{"class":506},[500,1146,1147],{"class":602},"DB",[500,1149,609],{"class":506},[500,1151,1152],{"class":602},"Host ",[500,1154,1155],{"class":506},"!=",[500,1157,1069],{"class":506},[500,1159,1072],{"class":630},[500,1161,897],{"class":506},[500,1163,596],{"class":506},[500,1165,1166,1169,1171,1174,1176,1178,1181,1185,1188,1190,1192,1194,1196,1198,1200,1202,1205,1207,1209,1211,1213],{"class":502,"line":573},[500,1167,1168],{"class":602},"        t",[500,1170,609],{"class":506},[500,1172,1173],{"class":696},"Errorf",[500,1175,1027],{"class":506},[500,1177,897],{"class":506},[500,1179,1180],{"class":630},"DB.Host = ",[500,1182,1184],{"class":1183},"swJcz","%q",[500,1186,1187],{"class":630},", want ",[500,1189,1184],{"class":1183},[500,1191,897],{"class":506},[500,1193,875],{"class":506},[500,1195,1142],{"class":602},[500,1197,609],{"class":506},[500,1199,1147],{"class":602},[500,1201,609],{"class":506},[500,1203,1204],{"class":602},"Host",[500,1206,875],{"class":506},[500,1208,1069],{"class":506},[500,1210,1072],{"class":630},[500,1212,897],{"class":506},[500,1214,576],{"class":506},[500,1216,1217],{"class":502,"line":579},[500,1218,1219],{"class":506},"    }\n",[500,1221,1222],{"class":502,"line":584},[500,1223,674],{"class":506},[500,1225,1226],{"class":502,"line":599},[500,1227,518],{"emptyLinePlaceholder":517},[500,1229,1230,1232,1235,1237,1239,1241,1243,1245,1247,1249],{"class":502,"line":615},[500,1231,1021],{"class":506},[500,1233,1234],{"class":696}," TestLoad_missingRequired",[500,1236,1027],{"class":506},[500,1238,1031],{"class":1030},[500,1240,1034],{"class":506},[500,1242,1037],{"class":510},[500,1244,609],{"class":506},[500,1246,1042],{"class":510},[500,1248,905],{"class":506},[500,1250,596],{"class":506},[500,1252,1253],{"class":502,"line":637},[500,1254,1255],{"class":908},"    \u002F\u002F DB_HOST intentionally not set\n",[500,1257,1258,1261,1263,1265,1267,1269,1271,1273,1275,1277,1279,1281],{"class":502,"line":650},[500,1259,1260],{"class":602},"    _",[500,1262,875],{"class":506},[500,1264,878],{"class":602},[500,1266,688],{"class":506},[500,1268,691],{"class":602},[500,1270,609],{"class":506},[500,1272,460],{"class":696},[500,1274,699],{"class":506},[500,1276,702],{"class":510},[500,1278,609],{"class":506},[500,1280,480],{"class":510},[500,1282,709],{"class":506},[500,1284,1285,1287,1289,1292,1295],{"class":502,"line":671},[500,1286,1139],{"class":524},[500,1288,878],{"class":602},[500,1290,1291],{"class":506},"==",[500,1293,1294],{"class":506}," nil",[500,1296,596],{"class":506},[500,1298,1300,1302,1304,1307,1309,1311,1314,1316],{"class":502,"line":1299},16,[500,1301,1168],{"class":602},[500,1303,609],{"class":506},[500,1305,1306],{"class":696},"Fatal",[500,1308,1027],{"class":506},[500,1310,897],{"class":506},[500,1312,1313],{"class":630},"expected an error for missing required DB_HOST",[500,1315,897],{"class":506},[500,1317,576],{"class":506},[500,1319,1321],{"class":502,"line":1320},17,[500,1322,1219],{"class":506},[500,1324,1326],{"class":502,"line":1325},18,[500,1327,674],{"class":506},[454,1329,1330,1331,1333,1334,1336,1337,1339,1340,1342,1343,1345],{},"No ",[458,1332,948],{}," file is involved here: ",[458,1335,1010],{}," sets real process environment variables for the duration of the test, exactly what ",[458,1338,460],{}," reads first (before falling back to any ",[458,1341,948],{}," value), so the test is deterministic regardless of whether a ",[458,1344,948],{}," file happens to exist in the working directory.",[471,1347,1349],{"id":1348},"with-the-framework","With the framework",[454,1351,1352,1353,1356,1357,461,1359,461,1361,1364,1365,1367,1368,1371],{},"A generated gpsystem project's ",[458,1354,1355],{},"internal\u002Fplatform\u002Fconfig"," package is exactly the composition pattern above, generated once and extended by ",[458,1358,91],{},[458,1360,116],{},[458,1362,1363],{},"add worker"," as modules are added. See ",[467,1366,164],{"href":190}," for the concept-level view (why configuration is an explicit, boot-time-only dependency in gpsystem) and ",[467,1369,1370],{"href":165},"Configuration reference"," for the full, generated-project-by-generated-project variable table.",[471,1373,1375],{"id":1374},"related-pages","Related pages",[1377,1378,1379,1396,1401],"ul",{},[1380,1381,1382,1385,1386,461,1388,461,1390,1392,1393,1395],"li",{},[467,1383,1384],{"href":265},"envconf: Overview",": ",[458,1387,460],{},[458,1389,464],{},[458,1391,797],{},", tags, ",[458,1394,948],{}," loading.",[1380,1397,1398,1400],{},[467,1399,164],{"href":190},": the composition principle and the env-prefix conventions across gp-system modules.",[1380,1402,1403,1405],{},[467,1404,1370],{"href":165},": every env variable, module by module.",[1407,1408,1409],"style",{},"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 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 .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 .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 .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}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 .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}",{"title":496,"searchDepth":514,"depth":514,"links":1411},[1412,1413,1414,1415,1416],{"id":473,"depth":514,"text":474},{"id":784,"depth":514,"text":785},{"id":998,"depth":514,"text":999},{"id":1348,"depth":514,"text":1349},{"id":1374,"depth":514,"text":1375},"Common envconf patterns: composition, prefixes, testing.","md",null,{},{"icon":192},{"title":268,"description":1417},"GTUEwCR-1ez4rkL1Ng-UdGAOHJDbOwbQPklY44NQOw4",[1425,1427],{"title":52,"path":265,"stem":266,"description":1426,"icon":192,"children":-1},"Typed environment configuration loading with struct tags.",{"title":52,"path":277,"stem":278,"description":1428,"icon":188,"children":-1},"Structured Go errors with stacks, codes and client-safe messages.",1787346809529]