Escape Hatches
The framework provides sensible defaults and a merge-based customization system for most needs. But sometimes you need full control. Escape hatches let you bypass framework automation entirely when the standard patterns do not fit.
When to use escape hatches
Consider an escape hatch when:
- Framework assumptions do not match your architecture - You have a non-standard service topology, custom routing requirements, or an unusual deployment pattern
- You need unsupported features - The framework does not expose configuration for a specific Kong plugin, Docker feature, or authentication flow
- Merge-based customization creates conflicts - The way your customizations interact with framework defaults causes problems
- You are migrating from another system - Your existing configuration does not map cleanly to framework conventions
Do not use escape hatches for:
- Simple additions - Adding a rate limiter, another plugin, or a new secret works fine with user files
- One-off overrides - Changing a single default value belongs in your user file
- Temporary experiments - Test changes in user files first; promote to escape hatch only if needed
Available escape hatches
Kong: kong.custom.yml
The most common escape hatch. When this file exists, the framework stops generating routes from your OpenAPI specs.
What happens:
- Framework detects
kong.custom.yml - Skips all automatic route generation
- Only resolves
${PLACEHOLDER}values from your secrets - Copies result to output locations
Create it:
Keep the global tsdevstack-strip-identity plugin and the trust header request-transformer in a custom config: they are what stops clients from forging identity headers. See Kong Customization for the full list.
Return to framework mode:
Kong image: kong-plugins/
The gateway's Dockerfile (infrastructure/kong/Dockerfile) and its .dockerignore are generated and overwritten by generate-kong, so they are not an escape hatch. To put your own Lua plugins in the gateway image, add them to the kong-plugins/ folder at the project root; they are built into the image locally and in the cloud. See Kong Plugins.
Docker: docker-compose.user.yml
Not strictly an escape hatch (it merges rather than replaces), but provides extensive control over local development.
What you can do:
- Add any service Docker supports
- Override any setting on framework services
- Mount custom volumes
- Change networking
See Docker Overrides for detailed examples.
Authentication: External OIDC
Bypass the framework's auth service entirely by using an external identity provider.
Configure in .tsdevstack/config.json:
Provide your OIDC discovery URL in .secrets.user.json:
What happens:
- Framework skips auth service generation
- No JWT keys are generated
- Kong validates tokens against your provider's JWKS
- Your provider handles all authentication flows
- Kong's OIDC plugin forwards your provider's token claims to services in
X-Userinfo; client-sent copies of that header are removed at the gateway bytsdevstack-strip-identity, so there is nothing to configure for header spoofing
Email: Custom provider
Replace the default Resend email provider with SendGrid, Mailgun, Postmark, or any other service by implementing the EmailProvider interface and overriding the EMAIL_PROVIDER injection token.
See Custom Email Provider for a full walkthrough with code examples and secrets setup.
Tradeoffs of breaking conventions
Using escape hatches involves tradeoffs. Understand these before committing.
Kong escape hatch tradeoffs
External OIDC tradeoffs
General tradeoffs
You gain:
- Full control over the specific area
- Ability to use features the framework does not expose
- Exact configuration matching your requirements
You lose:
- Automatic updates when the framework improves
- Consistency with framework conventions
- Some debugging support (framework cannot validate custom configs)
- Documentation alignment (guides assume standard setup)
How to stay upgradeable
Even with escape hatches, you can minimize upgrade friction.
Document your customizations
Create a CUSTOMIZATIONS.md in your project:
Keep escape hatches minimal
Use the smallest scope possible:
Track framework changes
When upgrading the framework:
- Read the changelog for changes to areas you have escaped
- Compare your custom config against new framework defaults
- Decide whether to adopt new patterns or maintain your approach
Consider returning to framework mode
Periodically evaluate whether your escape hatch is still necessary:
- Has the framework added support for what you needed?
- Have your requirements changed?
- Is the maintenance burden worth the customization?
To test returning to framework mode:
Migration strategies
From custom to framework
If the framework now supports what you needed:
- Audit your custom config - List every customization
- Map to framework features - Identify which map to user files, which are now defaults
- Create user file - Add necessary customizations to
kong.user.yml - Test thoroughly - Generate and compare before committing
- Remove escape hatch - Delete or rename the custom file
From framework to custom
If you need to escape:
- Generate current config - Run
npx tsdevstack generate-kongto see current output - Copy as starting point - Use
kong.ymlas yourkong.custom.ymlbase - Make your changes - Modify the copied config
- Test thoroughly - Ensure all routes work as expected
- Document the reasons - Future you will thank present you
Troubleshooting
Custom config not being used
Check that the file is named exactly right:
kong.custom.yml(notkong-custom.ymlorkong.custom.yaml)- File is in the project root
Secret placeholders not resolving
Ensure you use the exact syntax ${SECRET_NAME}:
- Correct:
${KONG_CORS_ORIGINS} - Wrong:
$KONG_CORS_ORIGINS,{{ KONG_CORS_ORIGINS }}
Cannot return to framework mode
If kong.custom.yml exists, the framework will not generate routes. Rename or delete it:
External OIDC not validating tokens
Verify:
- Discovery URL is accessible from Kong container
- Your tokens include the expected claims
- Audience and issuer match your provider configuration