Skip to main content

Upgrading to Codex 2.0

Codex 2.0 renames every configuration environment variable. Nothing else about your setup has to change: config files keep the same shape, and there is no database migration beyond the usual automatic one.

Codex will not start with the old names. That is deliberate. The alternative was to ignore them, which means a server running with default rate limits, the wrong port, or workers in a pod meant to serve web traffic, and no indication anything is wrong. A refusal at startup, listing exactly what to change, is the safer failure.

Before you upgrade

On 1.44 or later, ask the running version what will break:

codex config check

It prints every variable you set that changes, with its replacement. Prepare the edit, then apply it at the same time you bump the image tag.

Do not rename before upgrading

1.x does not read the new spelling. A variable renamed early is silently ignored, which is the failure mode this release exists to remove.

What changed, and why

The old scheme used a single _ for two different jobs: separating nesting levels, and separating words inside a key. Nothing in CODEX_RATE_LIMIT_ANONYMOUS_RPS says whether the section is rate_limit or rate, so every variable needed a hand-written rule, and adding a setting meant remembering to add one. Several documented variables never had one and did nothing at all.

Codex 2.0 separates nesting levels with __ and keeps _ for words within a key:

rate_limit.anonymous_rps       ->  CODEX_RATE_LIMIT__ANONYMOUS_RPS
database.postgres.max_connections -> CODEX_DATABASE__POSTGRES__MAX_CONNECTIONS
pdf_handle_cache.capacity -> CODEX_PDF_HANDLE_CACHE__CAPACITY

Settings that moved

These are not simple renames. Two invert their meaning, so read them carefully:

BeforeAfterNote
CODEX_COOKIE_SECURECODEX_AUTH__COOKIE_SECUREsame meaning
CODEX_DISABLE_WORKERSCODEX_TASK__RUN_IN_PROCESSinverted: DISABLE_WORKERS=true becomes RUN_IN_PROCESS=false
CODEX_IMAGE_DECODE_CONCURRENCYCODEX_IMAGES__DECODE_CONCURRENCYsame meaning
CODEX_MIGRATION_WAIT_INTERVALCODEX_DATABASE__MIGRATION_WAIT_INTERVAL_SECSsame meaning
CODEX_MIGRATION_WAIT_TIMEOUTCODEX_DATABASE__MIGRATION_WAIT_TIMEOUT_SECSsame meaning
CODEX_PLUGIN_ALLOWED_COMMANDSCODEX_PLUGINS__ALLOWED_COMMANDSsame meaning
CODEX_SKIP_MIGRATIONSCODEX_DATABASE__RUN_MIGRATIONSinverted: SKIP_MIGRATIONS=true becomes RUN_MIGRATIONS=false

All seven are now ordinary config keys, so they can live in codex.yaml instead of the environment.

Settings that stay environment-only

CODEX_ENCRYPTION_KEY, CODEX_SOURCE_DATABASE_URL and CODEX_TARGET_DATABASE_URL are unchanged.

Other behaviour changes

Values are typed, and a bad one stops the server. The old override layer hand-parsed each value and discarded anything it could not read, so CODEX_KOMGA_API_ENABLED=ture quietly meant false. Values are now parsed by type, and anything that does not fit is an error naming the variable.

This is the second thing to change when you upgrade, after the names:

TypeBeforeNow
boolean1, 0, yes, no, on, off, true, falsetrue or false
lista,b,c[a, b, c]
mapk1=v1,k2=v2{k1=v1, k2=v2}
numberunchangedunchanged
stringunchangedunchanged
# before
CODEX_API_CORS_ORIGINS=https://a.example,https://b.example
CODEX_OBSERVABILITY_OTLP_HEADERS=authorization=Bearer tok,x-tenant=acme
CODEX_KOMGA_API_ENABLED=1

# now
CODEX_API__CORS_ORIGINS='[https://a.example, https://b.example]'
CODEX_OBSERVABILITY__OTLP__HEADERS='{authorization="Bearer tok", x-tenant=acme}'
CODEX_KOMGA_API__ENABLED=true

Quote a map or list value that contains a space or a comma, since those delimit entries.

An empty value still means "unset", so blanking a variable to turn a setting off keeps working.

Parsing stops at the first bad value, so codex config check reports one type error at a time. The variable-name checks still run alongside it, so you will not have to fix them one restart apart.

Startup no longer writes a config file. Codex used to serialize its defaults to disk when the file was missing, which produced an uncommented dump and, because those defaults were read from the environment, could capture a database password in plaintext. Run codex config init for a commented starter instead.

New in this release

Local overlay. A codex.local.yaml beside your config is merged on top of it, so secrets and per-host tweaks no longer mean editing the committed file. It merges key by key; a list in the overlay replaces the base list rather than extending it.

TOML. Config files may be .toml as well as .yaml, chosen by extension.

PostgreSQL TLS. database.postgres.ssl_mode and friends are real settings. See Configuration. The libpq variables (PGSSLMODE and so on) still work when the Codex setting is unset.

Full rename table

Generated from the configuration schema, so it is exhaustive.

api

BeforeAfter
CODEX_API_API_DOCS_PATHCODEX_API__API_DOCS_PATH
CODEX_API_BASE_PATHCODEX_API__BASE_PATH
CODEX_API_CORS_ENABLEDCODEX_API__CORS_ENABLED
CODEX_API_CORS_ORIGINSCODEX_API__CORS_ORIGINS
CODEX_API_ENABLE_API_DOCSCODEX_API__ENABLE_API_DOCS
CODEX_API_MAX_PAGE_SIZECODEX_API__MAX_PAGE_SIZE

application

BeforeAfter
CODEX_APPLICATION_BASE_URLCODEX_APPLICATION__BASE_URL
CODEX_APPLICATION_HOSTCODEX_APPLICATION__HOST
CODEX_APPLICATION_PORTCODEX_APPLICATION__PORT

auth

BeforeAfter
CODEX_AUTH_ARGON2_MEMORY_COSTCODEX_AUTH__ARGON2_MEMORY_COST
CODEX_AUTH_ARGON2_PARALLELISMCODEX_AUTH__ARGON2_PARALLELISM
CODEX_AUTH_ARGON2_TIME_COSTCODEX_AUTH__ARGON2_TIME_COST
CODEX_AUTH_COOKIE_SECURECODEX_AUTH__COOKIE_SECURE
CODEX_AUTH_EMAIL_CONFIRMATION_REQUIREDCODEX_AUTH__EMAIL_CONFIRMATION_REQUIRED
CODEX_AUTH_JWT_EXPIRY_HOURSCODEX_AUTH__JWT_EXPIRY_HOURS
CODEX_AUTH_JWT_SECRETCODEX_AUTH__JWT_SECRET
CODEX_AUTH_OIDC_ALLOWED_REDIRECT_URISCODEX_AUTH__OIDC__ALLOWED_REDIRECT_URIS
CODEX_AUTH_OIDC_AUTO_CREATE_USERSCODEX_AUTH__OIDC__AUTO_CREATE_USERS
CODEX_AUTH_OIDC_DEFAULT_ROLECODEX_AUTH__OIDC__DEFAULT_ROLE
CODEX_AUTH_OIDC_ENABLEDCODEX_AUTH__OIDC__ENABLED
CODEX_AUTH_OIDC_PROVIDERSCODEX_AUTH__OIDC__PROVIDERS
CODEX_AUTH_OIDC_PROVIDERS_*_ROLE_MAPPINGCODEX_AUTH__OIDC__PROVIDERS__*__ROLE_MAPPING
CODEX_AUTH_OIDC_REDIRECT_URI_BASECODEX_AUTH__OIDC__REDIRECT_URI_BASE
CODEX_AUTH_REFRESH_TOKEN_ENABLEDCODEX_AUTH__REFRESH_TOKEN_ENABLED
CODEX_AUTH_REFRESH_TOKEN_EXPIRY_DAYSCODEX_AUTH__REFRESH_TOKEN_EXPIRY_DAYS

database

BeforeAfter
CODEX_DATABASE_DB_TYPECODEX_DATABASE__DB_TYPE
CODEX_DATABASE_MIGRATION_WAIT_INTERVAL_SECSCODEX_DATABASE__MIGRATION_WAIT_INTERVAL_SECS
CODEX_DATABASE_MIGRATION_WAIT_TIMEOUT_SECSCODEX_DATABASE__MIGRATION_WAIT_TIMEOUT_SECS
CODEX_DATABASE_POSTGRES_ACQUIRE_TIMEOUT_SECONDSCODEX_DATABASE__POSTGRES__ACQUIRE_TIMEOUT_SECONDS
CODEX_DATABASE_POSTGRES_BACKGROUND_MAX_CONNECTIONSCODEX_DATABASE__POSTGRES__BACKGROUND_MAX_CONNECTIONS
CODEX_DATABASE_POSTGRES_BATCH_FAN_OUTCODEX_DATABASE__POSTGRES__BATCH_FAN_OUT
CODEX_DATABASE_POSTGRES_DATABASE_NAMECODEX_DATABASE__POSTGRES__DATABASE_NAME
CODEX_DATABASE_POSTGRES_HOSTCODEX_DATABASE__POSTGRES__HOST
CODEX_DATABASE_POSTGRES_IDLE_TIMEOUT_SECONDSCODEX_DATABASE__POSTGRES__IDLE_TIMEOUT_SECONDS
CODEX_DATABASE_POSTGRES_MAX_CONNECTIONSCODEX_DATABASE__POSTGRES__MAX_CONNECTIONS
CODEX_DATABASE_POSTGRES_MAX_LIFETIME_SECONDSCODEX_DATABASE__POSTGRES__MAX_LIFETIME_SECONDS
CODEX_DATABASE_POSTGRES_MIN_CONNECTIONSCODEX_DATABASE__POSTGRES__MIN_CONNECTIONS
CODEX_DATABASE_POSTGRES_OPERATION_DEADLINE_SECONDSCODEX_DATABASE__POSTGRES__OPERATION_DEADLINE_SECONDS
CODEX_DATABASE_POSTGRES_PASSWORDCODEX_DATABASE__POSTGRES__PASSWORD
CODEX_DATABASE_POSTGRES_PORTCODEX_DATABASE__POSTGRES__PORT
CODEX_DATABASE_POSTGRES_SSL_CLIENT_CERTCODEX_DATABASE__POSTGRES__SSL_CLIENT_CERT
CODEX_DATABASE_POSTGRES_SSL_CLIENT_KEYCODEX_DATABASE__POSTGRES__SSL_CLIENT_KEY
CODEX_DATABASE_POSTGRES_SSL_MODECODEX_DATABASE__POSTGRES__SSL_MODE
CODEX_DATABASE_POSTGRES_SSL_ROOT_CERTCODEX_DATABASE__POSTGRES__SSL_ROOT_CERT
CODEX_DATABASE_POSTGRES_USERNAMECODEX_DATABASE__POSTGRES__USERNAME
CODEX_DATABASE_RUN_MIGRATIONSCODEX_DATABASE__RUN_MIGRATIONS
CODEX_DATABASE_SQLITE_ACQUIRE_TIMEOUT_SECONDSCODEX_DATABASE__SQLITE__ACQUIRE_TIMEOUT_SECONDS
CODEX_DATABASE_SQLITE_BACKGROUND_MAX_CONNECTIONSCODEX_DATABASE__SQLITE__BACKGROUND_MAX_CONNECTIONS
CODEX_DATABASE_SQLITE_BATCH_FAN_OUTCODEX_DATABASE__SQLITE__BATCH_FAN_OUT
CODEX_DATABASE_SQLITE_IDLE_TIMEOUT_SECONDSCODEX_DATABASE__SQLITE__IDLE_TIMEOUT_SECONDS
CODEX_DATABASE_SQLITE_MAX_CONNECTIONSCODEX_DATABASE__SQLITE__MAX_CONNECTIONS
CODEX_DATABASE_SQLITE_MAX_LIFETIME_SECONDSCODEX_DATABASE__SQLITE__MAX_LIFETIME_SECONDS
CODEX_DATABASE_SQLITE_MIN_CONNECTIONSCODEX_DATABASE__SQLITE__MIN_CONNECTIONS
CODEX_DATABASE_SQLITE_OPERATION_DEADLINE_SECONDSCODEX_DATABASE__SQLITE__OPERATION_DEADLINE_SECONDS
CODEX_DATABASE_SQLITE_PATHCODEX_DATABASE__SQLITE__PATH
CODEX_DATABASE_SQLITE_PRAGMASCODEX_DATABASE__SQLITE__PRAGMAS

email

BeforeAfter
CODEX_EMAIL_SMTP_FROM_EMAILCODEX_EMAIL__SMTP_FROM_EMAIL
CODEX_EMAIL_SMTP_FROM_NAMECODEX_EMAIL__SMTP_FROM_NAME
CODEX_EMAIL_SMTP_HOSTCODEX_EMAIL__SMTP_HOST
CODEX_EMAIL_SMTP_PASSWORDCODEX_EMAIL__SMTP_PASSWORD
CODEX_EMAIL_SMTP_PORTCODEX_EMAIL__SMTP_PORT
CODEX_EMAIL_SMTP_USERNAMECODEX_EMAIL__SMTP_USERNAME
CODEX_EMAIL_VERIFICATION_TOKEN_EXPIRY_HOURSCODEX_EMAIL__VERIFICATION_TOKEN_EXPIRY_HOURS
CODEX_EMAIL_VERIFICATION_URL_BASECODEX_EMAIL__VERIFICATION_URL_BASE

files

BeforeAfter
CODEX_FILES_PLUGINS_DIRCODEX_FILES__PLUGINS_DIR
CODEX_FILES_THUMBNAIL_DIRCODEX_FILES__THUMBNAIL_DIR
CODEX_FILES_UPLOADS_DIRCODEX_FILES__UPLOADS_DIR

images

BeforeAfter
CODEX_IMAGES_DECODE_CONCURRENCYCODEX_IMAGES__DECODE_CONCURRENCY

komga_api

BeforeAfter
CODEX_KOMGA_API_ENABLEDCODEX_KOMGA_API__ENABLED
CODEX_KOMGA_API_PREFIXCODEX_KOMGA_API__PREFIX

koreader_api

BeforeAfter
CODEX_KOREADER_API_ENABLEDCODEX_KOREADER_API__ENABLED

logging

BeforeAfter
CODEX_LOGGING_CONSOLECODEX_LOGGING__CONSOLE
CODEX_LOGGING_FILECODEX_LOGGING__FILE
CODEX_LOGGING_LEVELCODEX_LOGGING__LEVEL

observability

BeforeAfter
CODEX_OBSERVABILITY_BROWSER_ENABLEDCODEX_OBSERVABILITY__BROWSER__ENABLED
CODEX_OBSERVABILITY_BROWSER_PROXY_PATHCODEX_OBSERVABILITY__BROWSER__PROXY_PATH
CODEX_OBSERVABILITY_BROWSER_SAMPLE_RATIOCODEX_OBSERVABILITY__BROWSER__SAMPLE_RATIO
CODEX_OBSERVABILITY_ENABLEDCODEX_OBSERVABILITY__ENABLED
CODEX_OBSERVABILITY_METRICS_ENABLEDCODEX_OBSERVABILITY__METRICS__ENABLED
CODEX_OBSERVABILITY_METRICS_EXPORT_INTERVAL_MSCODEX_OBSERVABILITY__METRICS__EXPORT_INTERVAL_MS
CODEX_OBSERVABILITY_OTLP_ENDPOINTCODEX_OBSERVABILITY__OTLP__ENDPOINT
CODEX_OBSERVABILITY_OTLP_HEADERSCODEX_OBSERVABILITY__OTLP__HEADERS
CODEX_OBSERVABILITY_OTLP_PROTOCOLCODEX_OBSERVABILITY__OTLP__PROTOCOL
CODEX_OBSERVABILITY_OTLP_PROXY_ENDPOINTCODEX_OBSERVABILITY__OTLP__PROXY_ENDPOINT
CODEX_OBSERVABILITY_OTLP_TIMEOUT_MSCODEX_OBSERVABILITY__OTLP__TIMEOUT_MS
CODEX_OBSERVABILITY_SERVICE_NAMECODEX_OBSERVABILITY__SERVICE_NAME
CODEX_OBSERVABILITY_TRACES_ENABLEDCODEX_OBSERVABILITY__TRACES__ENABLED
CODEX_OBSERVABILITY_TRACES_SAMPLE_RATIOCODEX_OBSERVABILITY__TRACES__SAMPLE_RATIO

pdf

BeforeAfter
CODEX_PDF_CACHE_DIRCODEX_PDF__CACHE_DIR
CODEX_PDF_CACHE_RENDERED_PAGESCODEX_PDF__CACHE_RENDERED_PAGES
CODEX_PDF_JPEG_QUALITYCODEX_PDF__JPEG_QUALITY
CODEX_PDF_PDFIUM_LIBRARY_PATHCODEX_PDF__PDFIUM_LIBRARY_PATH
CODEX_PDF_RENDER_DPICODEX_PDF__RENDER_DPI

pdf_handle_cache

BeforeAfter
CODEX_PDF_HANDLE_CACHE_CAPACITYCODEX_PDF_HANDLE_CACHE__CAPACITY
CODEX_PDF_HANDLE_CACHE_ENABLEDCODEX_PDF_HANDLE_CACHE__ENABLED
CODEX_PDF_HANDLE_CACHE_IDLE_TTL_MINUTESCODEX_PDF_HANDLE_CACHE__IDLE_TTL_MINUTES
CODEX_PDF_HANDLE_CACHE_SWEEP_INTERVAL_SECONDSCODEX_PDF_HANDLE_CACHE__SWEEP_INTERVAL_SECONDS

plugins

BeforeAfter
CODEX_PLUGINS_ALLOWED_COMMANDSCODEX_PLUGINS__ALLOWED_COMMANDS

rate_limit

BeforeAfter
CODEX_RATE_LIMIT_ANONYMOUS_BURSTCODEX_RATE_LIMIT__ANONYMOUS_BURST
CODEX_RATE_LIMIT_ANONYMOUS_RPSCODEX_RATE_LIMIT__ANONYMOUS_RPS
CODEX_RATE_LIMIT_AUTHENTICATED_BURSTCODEX_RATE_LIMIT__AUTHENTICATED_BURST
CODEX_RATE_LIMIT_AUTHENTICATED_RPSCODEX_RATE_LIMIT__AUTHENTICATED_RPS
CODEX_RATE_LIMIT_BUCKET_TTL_SECSCODEX_RATE_LIMIT__BUCKET_TTL_SECS
CODEX_RATE_LIMIT_CLEANUP_INTERVAL_SECSCODEX_RATE_LIMIT__CLEANUP_INTERVAL_SECS
CODEX_RATE_LIMIT_ENABLEDCODEX_RATE_LIMIT__ENABLED
CODEX_RATE_LIMIT_EXEMPT_PATHSCODEX_RATE_LIMIT__EXEMPT_PATHS

scanner

BeforeAfter
CODEX_SCANNER_MAX_CONCURRENT_SCANSCODEX_SCANNER__MAX_CONCURRENT_SCANS

scheduler

BeforeAfter
CODEX_SCHEDULER_TIMEZONECODEX_SCHEDULER__TIMEZONE

task

BeforeAfter
CODEX_TASK_RUN_IN_PROCESSCODEX_TASK__RUN_IN_PROCESS
CODEX_TASK_WORKER_COUNTCODEX_TASK__WORKER_COUNT

Verifying

After upgrading:

codex config check

A clean run prints the resolved configuration with secrets redacted. As a Kubernetes initContainer, codex config check --strict --quiet fails the pod before the app container starts.