2025-10-22 Environment Variable Management

2025-10-22 Environment Variable Management

Date

Oct 22, 2025 

 Join our Cloud HD Video Meeting  

Attendees 

  • @Jenn Colt

  • @Kevin Day

  • @Shelley Doljack

  • @Olamide Kolawole

  • @Maccabee Levine

  • @Wayne Schneider

  • @Matt Weaver

Time

Item

Who

Notes

Time

Item

Who

Notes

1 min

Scribe

@Shelley Doljack

@Shelley Doljack is next, followed by @Jeff Gerhard

Reminder:  Please copy/paste the Zoom chat into the notes.  If you miss it, this is saved along with the meeting recording, but having it here has benefits.

3 min

Current State

ALL

FOLIO modules exhibit significant inconsistency in environment variable management:

Naming Inconsistencies:

  • S3/AWS Variables:

    • mod-users uses AWS_* prefix (AWS_URL, AWS_BUCKET, AWS_ACCESS_KEY_ID)

    • mod-bulk-operations uses S3_* prefix (S3_URL, S3_BUCKET, S3_ACCESS_KEY_ID)

    • mod-agreements/mod-licenses use GLOBAL_S3_SECRET_KEY(no other S3 env variables in these apps)

  • System User Variables: Mixed usage of SYSTEM_USER_NAME (mod-bulk-operations, mod-requests-mediated, mod-pubsub) vs SYSTEM_USER_USERNAME (mod-circulation-bff, mod-tlr, mod-search, mod-marc-migrations)

Documentation Gaps:

  • Well-documented modules (minority):

    • mod-users-keycloak: Comprehensive README tables with Name | Default | Required | Description

    • mod-data-export-spring: Simpler tables with Name | Default | Description

    • mod-agreements / mod-licenses / mod-serials: README table with Variable | Description | Options | Default

      • READMEs for these modules state that the table contains a ‘non-exhaustive list’ of environment variables

  • Undocumented modules (majority): Environment variables only in ModuleDescriptor.json with minimal or no description field

Configuration Approaches:

  • Most modules define env vars in descriptors/ModuleDescriptor-template.json

  • No standardized approach for required vs optional variables

Notes:

  • Brought up as a topic in the shoulder meeting at WOLFCon 25.

  • As a SysOps person, you should be able easily find these env vars.

  • The readme should have a list but not all of them do.

  • Modules that use common frameworks (like Spring or RMB), they don’t necessarily need to document environmental variables in their readme but maybe point to the framework.

15 min

Naming Standards & Conventions

 

  • What naming convention will we adopt as the standard?

Category

Inconsistency Found

Modules Affected

Recommendation Needed

S3/AWS Services

`AWS_*` vs `S3_*`

mod-users (AWS_*), mod-bulk-operations (S3_*)

Choose one prefix

System User

SYSTEM_USER_NAME vs SYSTEM_USER_USERNAME

mod-bulk-operations, mod-requests-mediated vs mod-circulation-bff, mod-tlr

Standardize on one

Database

DB_* (consistent)

All modules

✓ Already standardized

Kafka

KAFKA_* (consistent)

All modules

✓ Already standardized

Real Module Descriptor Examples:

// mod-users (AWS_* pattern) { "name": "AWS_URL", "value": "http://127.0.0.1:9000/" }, { "name": "AWS_REGION", "value": "" }, { "name": "AWS_BUCKET", "value": "example-bucket" }, { "name": "AWS_ACCESS_KEY_ID", "value": "AKIAIOSFODNN7EXAMPLE" }, { "name": "AWS_SECRET_ACCESS_KEY", "value": "wJalrXUtnFEMI/K7MDENG/EXAMPLEKEY" } // mod-bulk-operations (S3_* pattern) {"name": "S3_URL", "value": "http://127.0.0.1:9000/"}, {"name": "S3_REGION", "value": ""}, {"name": "S3_BUCKET", "value": "test-bucket2"}, {"name": "S3_ACCESS_KEY_ID", "value": "AKIAIOSFODNN7EXAMPLE"}, {"name": "S3_SECRET_ACCESS_KEY", "value": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"}

 

  • Do we grandfather existing variables or mandate migration?

    • Options

      • Hard cutoff: Set deadline, all modules must comply

      • Deprecation period: Support both old and new names with warnings for 2-3 releases

      • Grandfather clause: New modules only, existing modules migrate as able

 

Notes:

  • HTTP port env var - seems there are many different ways to configure it because of the framework used. We’re almost forced to use the variety due to the various frameworks used.

  • The goal is to provide a consistent experience for system operators.

  • AWS or S3? Some modules used a version of the dependency libraries that wanted S3 or AWS and that’s why we are where we are with that one.

  • When the framework changes, we should change our mapping and not have to change our environment variables.

  • Having AWS is sometimes useful so you know which modules depend on a cloud provider.

  • S3 makes more sense because you’re using the S3 API in order to use cloud storage.

  • We prefer S3_ .

  • We prefer SYSTEM_USER_NAME.

  • Side note re: system user, not sure if all modules allow you to set the system user username and not give the operator a chance to set it.

  • If system user name is configurable and an operator chooses one for all, it has security implications.

  • We want configuration to not be hardcoded and SYSTEM_USER_NAME is one of them.

  • Is there an easy way to get all the environment variables that folio modules use? Okapi might have a feature that gets the env vars.

  • Spring boot allows the application.yaml to have whatever env var you want but we should set it in the default to use other env variables and avoid Spring boot’s dynamic environment variable naming convention.

  • It would be nice to have our standard env var align with frameworks but that’s a big ask.

  • Sometimes DB_PORT is hardcoded (https://folio-org.atlassian.net/browse/KEYCLOAK-69 ).

  • Do we grandfather existing variables or mandate migration?

    • hard cutoff and deprecation aren’t really mutually exclusive.

    • The choice is really hard cutoff or grandfather. If we tell modules to comply, then we address deprecation.

    • Preference is support standardized env vars as well.

10 min

Documentation Requirements

 

What is the minimum acceptable documentation for each environment variable?

Current Best Practice Example (mod-users-keycloak):

Name

Default value

Required

Description

DB_HOST

localhost

false

Postgres hostname

DB_PORT

5432

false

Postgres port

KC_URL

  •  

true

Keycloak URL used to perform HTTP requests by KeycloakClient

SYSTEM_USER_RETRY_COUNT

10

false

Number of retry attempts to create a system user

Proposed Required Fields:

  • Name (required)

  • Default value (required, "-" if none)

  • Required/Optional flag (required)

  • Description (required, including purpose and valid values)

Where must it be documented?

Examples:

// Current minimal approach (mod-users) { "name": "DB_HOST", "value": "postgres" } // Better approach with description (mod-camunda) { "name": "OKAPI_URL", "value": "http://10.0.2.15:9130", "description": "The URL to the OKAPI service." }

Recommendation Needed:

  1. ModuleDescriptor mandatory + README optional?

  2. Both mandatory?

  3. README mandatory with detailed table format?

  4. ENV_VARS.md(link in the README.md) + ModuleDescriptor + Jira for Ops for automation from ModuleDescriptor

 

Notes:

  • Not all modules have a written list of env vars in their readme.

  • Proposed required fields, valid values should definitely be documented somewhere, either in the description column or another column.

  • Maybe keep to 4 columns b/c landscaping issues on github. Or have separate tables for required and for optional env vars.

  • We decided to keep it as 4 columns b/c that’s what some readmes currently have.

  • Where is must be documented: either human or machine-readable format.

  • If it’s in the module descriptor, we can write a tool that will generate it in a wiki for human-readable format.

  • History about why they’re in the module descriptor:

    • When building snapshot in okapi-based environments, they needed to be in the module descriptor in the LaunchDescriptor so that they are set when the container spins up, if they are required.

    • It serves as documentation but there is a technical reason why it is there now.

  • It is more likely that all the env vars a module uses will be in the module descriptor.

  • Kevin’s idea of a tool to generate a human-readable doc from the module descriptor sounds like a great idea. Could be added to CI.

  • If we tie the human-readable doc to being generated from the module descriptor, how would we make changes to env vars in order to be consistent?

  • TC should request the DevOps team to do this work.

  • ENV_VARS.md, the module descriptor would have to change a bit to include data about required fields, optional fields, etc.

  • How would we expect development teams to communicate deprecation?

    • It would be in the description field of the module descriptor.

  • Maybe add a deprecated property to the module descriptor?

    • We shouldn’t make any schema changes to module descriptors b/c it could be hairy to do.

    • Although technically, it shouldn’t be too hard a change.

    • We are trying to make our requirements easily-digestable to the FOLIO community.

  • Nobody is against option 4 for recommendations needed.

10 min

Mandatory vs. Optional Variables

 

What happens when required variables are missing?

Current Behavior (inconsistent):

  • Some modules: Fail fast on startup with exceptions

  • Some modules: Use default values silently

  • Some modules: Log warnings and continue with degraded functionality

mod-users-keycloak example (from README):

  • KC_URL marked as "Required: true" - module fails to start if missing

  • DB_HOST marked as "Required: false" with default "localhost"

Recommendation Needed:

  1. Fail fast: Module refuses to start, clear error message

  2. Default with warning: Use default value, log warning

  3. Tiered approach: Critical vars fail fast, optional vars use defaults

 

Notes:

  • If it’s using a default value, then it’s not a required variable.

  • Fail fast and loudly

  • Setting them as empty strings or is that considered not specified?

  • If the env is required and it is empty, it should throw an error.

  • Some env vars are booleans, so it’s different for application to application. Making too strong of an opinion could cause problems with 3rd party libraries we use.

  • Fail fast is great but we have this criteria in module evaluation that we should be able to handle failures better and not fail fast.

  • Fail fast is contradictory to our module evaluation criteria.

15 min

Migration Strategy

 

Breaking changes: How do we handle deprecated variables?

Example:

// Support both { "name": "OKAPI_URL", "value": "http://okapi:9130", "description": "DEPRECATED: Use GATEWAY_URL instead" }, { "name": "GATEWAY_URL", "value": "http://okapi:9130" } // Log warnings // Module logs: "WARNING: OKAPI_URL is deprecated, please use GATEWAY_URL" // Only new variable { "name": "GATEWAY_URL", "value": "http://okapi:9130" }

For new modules:

What criteria must be completed before acceptance?

Proposed Additional Module Evaluation Criteria:

  • [ ] All environment variables follow naming convention (DB_, KAFKA_, S3_/AWS_ per standard)

  • [ ] ModuleDescriptor includes description for each variable

  • [ ] README.md includes environment variable table with: Name | Default | Required | Description

  • [ ] Required vs optional variables clearly marked

  • [ ] Feature flags use consistent naming (e.g., *_ENABLED suffix)

  • [ ] Module startup validates required variables and fails fast with clear errors

 

Observability

 

Should modules log their configuration on startup?

Proposed Standard:

Startup Configuration Logging:

INFO Starting mod-bulk-operations v2.5.0 INFO Configuration loaded: INFO DB_HOST: postgres INFO DB_PORT: 5432 INFO DB_DATABASE: okapi_modules INFO DB_USERNAME: folio_admin INFO DB_PASSWORD: ******** (8 characters) INFO KAFKA_HOST: kafka INFO KAFKA_PORT: 9092 INFO S3_URL: http://minio:9000 INFO S3_BUCKET: bulk-operations INFO S3_ACCESS_KEY_ID: AKIA******AMPLE (redacted) INFO S3_SECRET_ACCESS_KEY: ******** (40 characters) INFO SYSTEM_USER_ENABLED: true INFO ENV: folio

Benefits:

  • Easier debugging of configuration issues

  • Confirms which values are actually being used

  • Validates env vars were loaded correctly

  • Helps identify missing or default values in production

Security Considerations:

  • Passwords: Show only character count

  • API Keys/Tokens: Show first 4 and last 4 characters with middle redacted

Standardized Error Messages

Current Problem: Inconsistent error messages when env vars are misconfigured

Proposed Standard Error Format:

ERROR: Required environment variable missing Variable: DB_PASSWORD Description: Postgres database password Required: true Documentation: See https://github.com/folio-org/mod-bulk-operations#environment-variables ERROR: Invalid environment variable value Variable: DB_PORT Current Value: "invalid" Expected Type: integer (1-65535) Documentation: See https://github.com/folio-org/mod-bulk-operations#environment-variables ERROR: Environment variable connection test failed Variable: OKAPI_URL Current Value: http://okapi:9130 Error: Connection refused Suggestion: Verify that Okapi is running and accessible at this URL

Benefits:

  • Faster troubleshooting

  • Clearer guidance for operators

  • Consistent experience across all modules

  • Links to documentation

 

Enforcement

 

What can we do to ensure continuous adherence?

NA

Zoom Chat

 

2025-10-22 09:17:31 From Wayne Schneider to Everyone:
mod-users is one of the most recent S3 implementations but maybe the devs missed the memo

2025-10-22 09:18:16 From Day, Kevin to Everyone:
This is the old meeting regarding environment variable naming.
It included KC_ vs KEYCLOAK_ and possibly others:
https://folio-org.atlassian.net/wiki/spaces/TC/pages/1052442627

2025-10-22 09:18:50 From Day, Kevin to Everyone:
GLOBAL_S3_SECRET_KEY
Is a weird one.
Wayne Schneider:😦

2025-10-22 09:23:16 From Day, Kevin to Everyone:
This is a link to where FOLIO_SYSTEM_USER_USERNAME (really) is being referenced:
mod-roles-keycloak/README.md at 73c3f0efb58022ad462b0521697227d2ba799b43 · folio-org/mod-roles-keycloak

2025-10-22 09:36:28 From Wayne Schneider to Everyone:
Please not the wiki, please the README
Matt Weaver:❤️
Day, Kevin:👍

2025-10-22 09:47:02 From Wayne Schneider to Everyone:
The work would be something for the FOLIO DevOps team

2025-10-22 09:58:19 From Maccabee Levine to Everyone:
There is a module review criterion "Gracefully handles the absence of third party systems or related configuration. (3, 5, 12)"

2025-10-22 09:59:41 From Day, Kevin to Everyone:
Fail fast would require a migration guide, probably.

2025-10-22 09:59:41 From Matt Weaver to Everyone:
One example on my team, which is a bit of a balancing act: mod-lists requires S3 to be configured, and will fail fast if it’s not set up right. But you can disable that fail-fast behavior with another environment var