The fastest API Gateway in the market, ready to run on premises, cloud, or hybrid.
The gateway sits in front of your microservices to provide access control, security, throttling, analytics, and much more. KrakenD is not only a proxy but a Backend for Frontend that can aggregate and transform multiple calls simultaneously, avoiding network traffic and reducing bandwidth consumer to the end-user.
KrakenD can be set up in a single krakend.json file. A single, massive krakend.json with hardcoded backends is an anti-pattern. Pros treat gateway configurations like clean, modular code.
1. The Directory Structure
Instead of one file, we’re splitting gateway configuration by domain, environments, and general settings which keeps it dynamic and organized as well.
├── .env
├── .gitignore
├── docker-compose.yml
└── config/
├── krakend.tmpl
├── settings/
│ ├── dev
| | ├── hosts.json
│ └── prod
| └── hosts.json
└── endpoints/
├── products.tmpl
└── users.tmpl
2. Step-by-Step Implementation
Step 1: Container Orchestration (docker-compose.yml)
Instruct KrakenD to enable Flexible Configuration (FC_ENABLE), declare the directory where your modular endpoint templates live (FC_TEMPLATES), and point to your environment variables (FC_SETTINGS).
services:
gateway:
container_name: api-gateway
image: krakend:2.13.8
ports:
- "3000:3000"
volumes:
- ./config:/etc/krakend:ro
environment:
- FC_ENABLE=1
- FC_TEMPLATES=/etc/krakend/endpoints
- FC_SETTINGS=/etc/krakend/settings/dev
command: ["run", "-c", "/etc/krakend/krakend.tmpl"]
restart: unless-stopped
FC_ENABLE=1: Tells KrakenD to turn on the template engine.
FC_TEMPLATES: Points to the directory containing your modular template files (like your endpoints/ folder).
FC_SETTINGS: Points to the file or directory containing your environment variables (like hosts.json).
Step 2: Environment Settings (config/settings/dev/hosts.json)
Use this file to store microservice host URLs and environment-specific strings, keeping them out of your main routing logic.
{
"hosts": {
"product_service": "http://product-api:5001",
"user_service": "http://user-api:5002"
}
}
Step 3: Modular Endpoints (config/endpoints/users.tmpl)
Define template configurations using standard Go templating.
{
"endpoint": "/api/auth/register",
"method": "POST",
"backend": [{
"url_pattern": "/api/auth/register",
"host": ["{{ .hosts.user_service }}"]
}]
},
{
"endpoint": "/api/auth/login",
"method": "POST",
"backend": [{
"url_pattern": "/api/auth/login",
"host": ["{{ .hosts.user_service }}"]
}]
}
Notice how we reference
"{{ .hosts.user_service }}"? At build time, KrakenD compiles this template and automatically swaps that placeholder with the URL from your environment settings file (hosts.json).
Q. what is this .tmpl file?
A: .tmpl (Template) file is a plain text blueprint containing static configuration mixed with dynamic placeholders (like {{ .hosts.user_service }}).
It leverages Go's templating engine to act as a flexible skeleton before the final configuration is compiled.
Example:
1. Template (users.tmpl):
"host": [ "{{ .hosts.user_service }}" ]
2. Variables (hosts.json):
{
"product_service": "http://localhost:5001",
"user_service": "http://localhost:5002"
}
3. What KrakenD actually runs in memory:
"host": [ "http://localhost:5002" ]
Q. "host": [ "{{ .hosts.user_service }}" ] how is it getting the user service url with that?
A: It works via KrakenD's Flexible Configuration(FC) engine during container startup. It executes in two quick steps:
The Flag: In your
docker-compose.yml, you setFC_SETTINGS=/etc/krakend/settings/dev. This forces KrakenD to load yourhosts.jsonfile into memory as the core data dictionary.The Evaluation: As KrakenD compiles the configuration, it encounters the template syntax
{{ .hosts.user_service }}. The dot (.) represents the root of your loadedhosts.jsonfile. It navigates down the keys:hosts→user_service, extracts the string"http://user-api:5002", and replaces the placeholder entirely before compiling the route.
Step 4: The Entrypoint (config/krakend.tmpl)
Tie everything together into the main skeleton. KrakenD will pull the files from your FC_TEMPLATES (defined in docker compose file) directory and compile them here.
{
"version": 3,
"port": 8080,
"timeout": "3s",
"endpoints": [
{{ template "products.tmpl" . }},
{{ template "users.tmpl" . }}
]
}
Now let's go a little bit further: extra_config
extra_config helps to enable and configure plugins, middleware, and extended features. It unlocks advanced capabilities such as security, rate limiting, logging and metrics.
krakend.tmpl
{
"version": 3,
"port": 8080,
"timeout": "3s",
"endpoints": [
{{ template "products.tmpl" . }},
{{ template "users.tmpl" . }}
],
"extra_config": {
"telemetry/logging": {
"level": "INFO",
"prefix": "[KRAKEND]",
"stdout": true
},
"security/cors": {
"allow_origins": ["*"],
"allow_methods": ["GET", "POST", "PUT", "PATCH", "DELETE"],
"allow_headers": ["Authorization", "Content-Type"]
}
}
}
In krakend.tmpl we are using it for logging and security(to handle cors).
user.tmpl
{
"endpoint": "/api/auth/register",
"method": "POST",
"extra_config": {
"qos/ratelimit/router": { "max_rate": 200, "capacity": 200, "every": "1s" }
},
"backend": [{
"url_pattern": "/api/auth/register",
"host": ["{{ .hosts.user_service }}"],
"extra_config": {
"qos/circuit-breaker": { "max_errors": 10, "interval": 60, "timeout": 30, "name": "cb-users-post-register", "log_status_change": true }
}
}]
},
{
"endpoint": "/api/auth/login",
"method": "POST",
"extra_config": {
"qos/ratelimit/router": { "max_rate": 200, "capacity": 200, "every": "1s" }
},
"backend": [{
"url_pattern": "/api/auth/login",
"host": ["{{ .hosts.user_service }}"],
"extra_config": {
"qos/circuit-breaker": { "max_errors": 10, "interval": 60, "timeout": 30, "name": "cb-users-post-login", "log_status_change": true }
}
}]
}
Here, we are using it for rate limiting and circuit-breaker.
rate limiting: 200 request per sec
circuit-breaker: Oh boy! it's on whole another level. Let's talk in detail below.
Circuit Breaker
It's job is to STOP KrakenD from sending requests to a failing service, giving that service time to recover and preventing a total system crash.
"extra_config": {
"qos/circuit-breaker": {
"max_errors": 10,
"interval": 60,
"timeout": 30,
"name": "cb-users-post-login",
"log_status_change": true
}
}
How above specific setting works
Closed: Closed is a healthy state, it means circuit breaker is close and requests can pass normally.
Open: If KrakenD counts max_error(10 errors) within time interval(60s), it blocks all the requests to the backend server.
Half Open: After the 30-second timeout expires, the circuit breaker enters the Half-Open state. In that state, it allows to pass limited number of requests to test if the backend is actually stable. If the test passes, Circuit Breaker goes in Close state else goes in Open state.
Some unexplained configs in the circuit breaker
name: A friendly name to follow this circuit breaker's activity in the logs.
log_status_change: Whether to log the changes of state of this circuit breaker or not. Default to false.
More features provided by KrakenD
1. Data Manipulation & Aggregation: Merge multiple microservice responses into a single JSON object.
2. Authentication Offloading: Native JWT validation plugins allow the gateway to reject unauthorized requests at the edge before they even touch your internal networks.
3. Response Caching: In-memory or Redis caching options.
4. Comprehensive Metrics: Native integration with Prometheus, Jaeger, OpenTelemetry, and ELK stack for plug-and-play system visibility.
As I implement more features, I'll update this setup. How are you currently managing your API Gateway configurations? Let me know in the comments!

Top comments (0)