[{"data":1,"prerenderedAt":499},["ShallowReactive",2],{"doc-\u002Fdocs\u002Fself-hosting\u002Fenvironment-variables":3,"github-stars":496},{"id":4,"title":5,"body":6,"description":487,"extension":488,"meta":489,"navigation":490,"order":480,"path":491,"section":492,"seo":493,"stem":494,"__hash__":495},"docs\u002Fdocs\u002Fself-hosting\u002Fenvironment-variables.md","Environment variables",{"type":7,"value":8,"toc":476},"minimark",[9,13,17,37,42,45,128,133,162,165,169,177,216,229,233,246,340,344,347,421,425,428,458,472],[10,11,5],"h1",{"id":12},"environment-variables",[14,15,16],"p",{},"Clerq is configured entirely through environment variables, so the same build\nruns in development, staging and production. This page lists every variable\nthe app actually reads. If a setting is not on this page, the app does not\nread it.",[14,18,19,20,24,25,28,29,32,33,36],{},"When you run the bundled ",[21,22,23],"code",{},"docker-compose.yml",", the compose-level variables in\nthe last section are assembled into the application variables for you - you\ngenerally only set ",[21,26,27],{},"POSTGRES_PASSWORD",", ",[21,30,31],{},"BETTER_AUTH_SECRET"," and\n",[21,34,35],{},"BETTER_AUTH_URL",".",[38,39,41],"h2",{"id":40},"application-variables","Application variables",[14,43,44],{},"These are read by the app (and the migration step) at runtime.",[46,47,48,64],"table",{},[49,50,51],"thead",{},[52,53,54,58,61],"tr",{},[55,56,57],"th",{},"Variable",[55,59,60],{},"Required",[55,62,63],{},"What it does",[65,66,67,97,108],"tbody",{},[52,68,69,75,78],{},[70,71,72],"td",{},[21,73,74],{},"DATABASE_URL",[70,76,77],{},"yes",[70,79,80,81,84,85,88,89,92,93,96],{},"PostgreSQL connection string, e.g. ",[21,82,83],{},"postgresql:\u002F\u002Fclerq:password@host:5432\u002Fclerq",". Read by the app and by ",[21,86,87],{},"drizzle-kit"," when applying migrations. Under docker-compose this is built for you from the ",[21,90,91],{},"POSTGRES_*"," values and points at the internal ",[21,94,95],{},"postgres"," service - you do not set it yourself there.",[52,98,99,103,105],{},[70,100,101],{},[21,102,31],{},[70,104,77],{},[70,106,107],{},"Secret key used to sign session cookies and the short-lived signed invoice-PDF download links. Use at least 32 random characters. Rotating it signs everyone out and invalidates any outstanding PDF links.",[52,109,110,114,117],{},[70,111,112],{},[21,113,35],{},[70,115,116],{},"yes in production",[70,118,119,120,123,124,127],{},"The external base URL your instance is reached on, e.g. ",[21,121,122],{},"https:\u002F\u002Fclerq.example.com",". Used for authentication callbacks and redirects. It must match the scheme, host and port your users actually use. Defaults to ",[21,125,126],{},"http:\u002F\u002Flocalhost:3000"," for local runs.",[129,130,132],"h3",{"id":131},"generating-better_auth_secret","Generating BETTER_AUTH_SECRET",[134,135,140],"pre",{"className":136,"code":137,"language":138,"meta":139,"style":139},"language-bash shiki shiki-themes github-dark","openssl rand -base64 32\n","bash","",[21,141,142],{"__ignoreMap":139},[143,144,147,151,155,159],"span",{"class":145,"line":146},"line",1,[143,148,150],{"class":149},"svObZ","openssl",[143,152,154],{"class":153},"sU2Wk"," rand",[143,156,158],{"class":157},"sDLfK"," -base64",[143,160,161],{"class":157}," 32\n",[14,163,164],{},"The app logs a warning if the secret is shorter than 32 characters or looks\nlow-entropy. Treat that warning as an error for any instance other people can\nreach.",[38,166,168],{"id":167},"optional-google-sign-in","Optional: Google sign-in",[14,170,171,172,176],{},"Google SSO is strictly optional. Self-hosting never requires a third-party\naccount - email and password sign-in always works. The Google button only\nappears when ",[173,174,175],"strong",{},"both"," variables below are set; leave them unset to hide it.",[46,178,179,189],{},[49,180,181],{},[52,182,183,185,187],{},[55,184,57],{},[55,186,60],{},[55,188,63],{},[65,190,191,204],{},[52,192,193,198,201],{},[70,194,195],{},[21,196,197],{},"GOOGLE_CLIENT_ID",[70,199,200],{},"no",[70,202,203],{},"OAuth client ID from Google Cloud. Enables the \"Continue with Google\" button when paired with the secret.",[52,205,206,211,213],{},[70,207,208],{},[21,209,210],{},"GOOGLE_CLIENT_SECRET",[70,212,200],{},[70,214,215],{},"OAuth client secret that pairs with the client ID above.",[14,217,218,219,222,223,228],{},"The authorized redirect URI to register with Google is\n",[21,220,221],{},"\u003CBETTER_AUTH_URL>\u002Fapi\u002Fauth\u002Fcallback\u002Fgoogle",". See\n",[224,225,227],"a",{"href":226},"\u002Fdocs\u002Fself-hosting\u002Fproduction","Going to production"," for the full setup.",[38,230,232],{"id":231},"compose-level-variables","Compose-level variables",[14,234,235,236,238,239,241,242,245],{},"These are read by the bundled ",[21,237,23],{}," itself (not by the app\ndirectly). Compose uses them to build the database, bind host ports, and\nconstruct ",[21,240,74],{},". Set them in the ",[21,243,244],{},".env"," file next to the compose\nfile.",[46,247,248,259],{},[49,249,250],{},[52,251,252,254,257],{},[55,253,57],{},[55,255,256],{},"Default",[55,258,63],{},[65,260,261,276,292,306,325],{},[52,262,263,268,273],{},[70,264,265],{},[21,266,267],{},"POSTGRES_USER",[70,269,270],{},[21,271,272],{},"clerq",[70,274,275],{},"Database role the app connects as.",[52,277,278,282,286],{},[70,279,280],{},[21,281,27],{},[70,283,284],{},[21,285,272],{},[70,287,288,289],{},"Database password. ",[173,290,291],{},"Change this before exposing the instance anywhere.",[52,293,294,299,303],{},[70,295,296],{},[21,297,298],{},"POSTGRES_DB",[70,300,301],{},[21,302,272],{},[70,304,305],{},"Database name.",[52,307,308,313,318],{},[70,309,310],{},[21,311,312],{},"POSTGRES_PORT",[70,314,315],{},[21,316,317],{},"5432",[70,319,320,321,324],{},"Host port the database is published on, bound to ",[21,322,323],{},"127.0.0.1"," only.",[52,326,327,332,337],{},[70,328,329],{},[21,330,331],{},"APP_PORT",[70,333,334],{},[21,335,336],{},"3000",[70,338,339],{},"Host port mapped to the app container's port 3000.",[38,341,343],{"id":342},"set-automatically-by-the-image","Set automatically by the image",[14,345,346],{},"The production image sets these for you. You normally never change them, but\nthey are listed here so nothing is hidden.",[46,348,349,360],{},[49,350,351],{},[52,352,353,355,358],{},[55,354,57],{},[55,356,357],{},"Value",[55,359,63],{},[65,361,362,377,391,406],{},[52,363,364,369,374],{},[70,365,366],{},[21,367,368],{},"NODE_ENV",[70,370,371],{},[21,372,373],{},"production",[70,375,376],{},"Standard Node production mode.",[52,378,379,384,388],{},[70,380,381],{},[21,382,383],{},"PORT",[70,385,386],{},[21,387,336],{},[70,389,390],{},"Port the app listens on inside the container.",[52,392,393,398,403],{},[70,394,395],{},[21,396,397],{},"HOSTNAME",[70,399,400],{},[21,401,402],{},"0.0.0.0",[70,404,405],{},"Binds to all interfaces inside the container.",[52,407,408,413,418],{},[70,409,410],{},[21,411,412],{},"NEXT_TELEMETRY_DISABLED",[70,414,415],{},[21,416,417],{},"1",[70,419,420],{},"Disables Next.js telemetry.",[38,422,424],{"id":423},"what-clerq-does-not-need","What Clerq does not need",[14,426,427],{},"To save you searching for settings that do not exist:",[429,430,431,438,444,450],"ul",{},[432,433,434,437],"li",{},[173,435,436],{},"No SMTP or email configuration."," Clerq sends no email. Team invitations\nare shareable links you send yourself, and invoices are exported as PDFs\nrather than emailed. There is no mail server to configure.",[432,439,440,443],{},[173,441,442],{},"No currency-API key."," Exchange rates come from the European Central\nBank's public reference rates, fetched server-side with no key and no\naccount.",[432,445,446,449],{},[173,447,448],{},"No object storage."," Logos and expense receipts are stored inline in the\ndatabase, so there is no S3 bucket or blob store to run.",[432,451,452,455,456,36],{},[173,453,454],{},"No sign-up toggle today."," There is no environment variable to disable new\nregistrations. If your instance is internet-facing and you do not want open\nsign-ups, put it behind your own access control - see\n",[224,457,227],{"href":226},[459,460,461],"blockquote",{},[14,462,463,464,28,466,468,469,471],{},"The shortest viable production config is three lines:\n",[21,465,27],{},[21,467,31],{}," and ",[21,470,35],{},". Everything\nelse has a working default.",[473,474,475],"style",{},"html pre.shiki code .svObZ, html code.shiki .svObZ{--shiki-default:#B392F0}html pre.shiki code .sU2Wk, html code.shiki .sU2Wk{--shiki-default:#9ECBFF}html pre.shiki code .sDLfK, html code.shiki .sDLfK{--shiki-default:#79B8FF}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);}",{"title":139,"searchDepth":477,"depth":477,"links":478},3,[479,483,484,485,486],{"id":40,"depth":480,"text":41,"children":481},2,[482],{"id":131,"depth":477,"text":132},{"id":167,"depth":480,"text":168},{"id":231,"depth":480,"text":232},{"id":342,"depth":480,"text":343},{"id":423,"depth":480,"text":424},"Every environment variable Clerq reads, what it does, whether it is required, and safe values - so the same image runs in every environment.","md",{},true,"\u002Fdocs\u002Fself-hosting\u002Fenvironment-variables","Self-hosting",{"title":5,"description":487},"docs\u002Fself-hosting\u002Fenvironment-variables","yFmz3iGtqxtiKGG6UynRC31fxQHHrn98kZrqGR8qQpc",{"stars":497,"repo":498},0,"PunterDigital\u002Fclerq",1781535397976]