Documentation

Redis to Adapters Migration

New
Browse documentation

Published 2026-08-13. V2 is a prerelease; the web core is release-gated and other previews are named separately. What beta means.

Read this page as HTML, Markdown, or structured JSON—or open the published Markdown with an AI assistant. Gemini receives the prompt through your clipboard because its signed-out page does not reliably prefill URL text; paste when the new tab opens. External assistants need the public site URL.

1.4.1
Unavailable in this version
1.5
Unavailable in this version

Migrating from Redis to Adapters

Amber V2 removes Redis as a mandatory framework dependency. The framework ships in-memory session and pub/sub adapters; it does not ship a first-party Redis implementation. Applications that still need Redis must implement and register adapters against the Amber interfaces.

This migration changes how Amber reaches the storage or message broker. It does not require you to stop using Redis.

Where the examples go

  • built-in adapter names go in config/environments/development.yml, test.yml, or the environment being changed;
  • application adapter classes go under src/adapters/, for example src/adapters/redis_session_adapter.cr;
  • adapter registration belongs in config/application.cr before Amber builds its session or pub/sub services; and
  • commands and specs run from the application root beside shard.yml.

Choose the target behavior

Requirement Suitable direction
Local development and tests Built-in memory adapters
One application process where losing process-local state is acceptable Built-in memory adapters after explicit verification
Sessions shared across processes or hosts Registered external session adapter
WebSocket broadcasts shared across processes or hosts Registered external pub/sub adapter
Existing Redis-backed production behavior Custom Redis adapters or another verified shared backend

The memory adapters are process-local. Do not use them as a silent replacement for shared Redis state in a horizontally scaled deployment.

Inventory the Amber 1.x contract

Before changing configuration, record:

  • the session cookie name, signing or encryption behavior, expiration, and rotation rules;
  • the Redis key and channel namespaces;
  • the serialized session and pub/sub payload formats;
  • whether users or broadcasts must survive a process restart;
  • every application process that reads sessions or subscribes to broadcasts;
  • cleanup jobs, Redis ACLs, TLS settings, and monitoring tied to the old keys.

Keep a deployable copy of the current configuration while the replacement is tested.

Built-in memory configuration

The clean V2 application selects the built-in adapters by name:

YAML
# config/environments/development.yml
session:
  key: "my_app.session"
  store: "signed_cookie"
  adapter: "memory"
  expires: 3600

pubsub:
  adapter: "memory"

Use this path for development, tests, or a deployment whose process-local state is an intentional constraint. Restart the application during testing to prove that the resulting state loss is acceptable.

Keep Redis through a custom session adapter

A shared session backend implements Amber::Adapters::SessionAdapter:

Crystal
abstract class Amber::Adapters::SessionAdapter
  abstract def get(session_id : String, key : String) : String?
  abstract def set(session_id : String, key : String, value : String) : Nil
  abstract def delete(session_id : String, key : String) : Nil
  abstract def destroy(session_id : String) : Nil
  abstract def exists?(session_id : String, key : String) : Bool
  abstract def keys(session_id : String) : Array(String)
  abstract def values(session_id : String) : Array(String)
  abstract def to_hash(session_id : String) : Hash(String, String)
  abstract def empty?(session_id : String) : Bool
  abstract def expire(session_id : String, seconds : Int32) : Nil
  abstract def batch_set(session_id : String, values : Hash(String, String)) : Nil
  abstract def batch(session_id : String, &block : Amber::Adapters::SessionBatchOperations ->) : Nil
end

Register the application implementation before Amber builds the session store:

Crystal
# config/application.cr
require "amber"
require "../src/adapters/redis_session_adapter"

Amber::Adapters::AdapterFactory.register_session_adapter("redis") do
  RedisSessionAdapter.new(redis_client)
end

Then select the registered name in the environment configuration:

YAML
session:
  key: "my_app.session"
  store: "signed_cookie"
  adapter: "redis"
  expires: 86400

The Session Adapters guide documents the complete interface and registration contract. Compile and contract-test the application adapter against the exact Redis shard version it uses.

Keep cross-process broadcasts through a custom pub/sub adapter

A shared message backend implements Amber::Adapters::PubSubAdapter:

Crystal
abstract class Amber::Adapters::PubSubAdapter
  abstract def publish(topic : String, sender_id : String, message : JSON::Any) : Nil
  abstract def subscribe(topic : String, &block : (String, JSON::Any) -> Nil) : Nil
  abstract def unsubscribe(topic : String) : Nil
  abstract def unsubscribe_all : Nil
  abstract def close : Nil
end

Register and select the application implementation:

Crystal
# config/application.cr
require "amber"
require "../src/adapters/redis_pubsub_adapter"

Amber::Adapters::AdapterFactory.register_pubsub_adapter("redis") do
  RedisPubSubAdapter.new(redis_client)
end
YAML
pubsub:
  adapter: "redis"

The PubSub Adapters guide covers registration and multi-process behavior. Test with at least two application processes; a single-process browser test cannot prove cross-process delivery.

Preserve or retire existing sessions deliberately

Changing a session backend can invalidate every active session. Choose one of these policies before deployment:

  • preserve the existing Redis key namespace and serialization in the new adapter;
  • deploy a temporary dual-read migration that moves a session after a successful old-format read;
  • schedule a coordinated logout and communicate it as an intentional product change.

Do not assume that forcing every user to sign in again is harmless. Account recovery, long-running work, carts, CSRF state, and administrative sessions may make session loss operationally significant.

Cutover sequence

  1. Add the adapter implementation and its dependency without removing the old Redis configuration.
  2. Contract-test every adapter method, expiration behavior, malformed payload, connection failure, and reconnect path.
  3. Exercise login, logout, session rotation, and WebSocket broadcasts in a staging deployment that matches the production process count.
  4. Apply the chosen active-session migration policy.
  5. Switch the Amber configuration to the registered adapter name.
  6. Monitor adapter errors, Redis connections, session failures, and broadcast delivery through the rollback window.

Removing Redis after the cutover

Remove Redis only after confirming that no application process, job worker, cache, rate limiter, session store, or pub/sub subscriber still uses it. Inspect the shard dependencies, environment variables, deployment manifests, secrets, monitoring, and infrastructure configuration before retiring the service.

Keep the previous configuration and deployment artifact available until the replacement has passed its production verification window.

Verification checklist

  • Session create, read, update, delete, destroy, and expiration behavior pass.
  • Login, logout, rotation, and invalid-cookie behavior pass.
  • Restart behavior matches the chosen state policy.
  • Broadcasts reach subscribers in a second application process.
  • Redis authentication, TLS, ACLs, timeouts, and reconnect behavior are tested when Redis remains.
  • The active-session migration or coordinated logout is documented.
  • The previous configuration can be restored without a code rewrite.