Embedding Temporal server as a Go library
You can run Temporal server as an embedded Go library instead of deploying it as a separate service. This approach is useful for testing and development scenarios where you want to run Temporal in-process without managing external infrastructure.
Embedded deployments with SQLite are suitable for testing and development only. For production workloads, deploy Temporal as a service using MySQL, PostgreSQL, or Cassandra as the persistence layer.
Reference implementation
The recommended way to run an embedded Temporal server is to use the Temporal CLI's dev server implementation as a reference. The CLI's devserver package provides a complete implementation that handles:
- SQLite configuration and schema setup
- Namespace creation
- Service configuration
- Port allocation
You can study and adapt this implementation for your own embedded use case.
Basic server API
The core API for embedding Temporal is temporal.NewServer():
import (
"go.temporal.io/server/temporal"
"go.temporal.io/server/common/config"
)
server, err := temporal.NewServer(
temporal.ForServices(temporal.DefaultServices),
temporal.WithConfig(cfg),
temporal.InterruptOn(temporal.InterruptCh()),
)
if err != nil {
log.Fatal(err)
}
if err := server.Start(); err != nil {
log.Fatal(err)
}
The challenge is building the config.Config struct correctly, especially for SQLite which requires:
- Schema setup - SQLite databases need schema initialization via
sqliteschema.SetupSchema() - Namespace creation - Namespaces can be pre-created via
sqliteschema.CreateNamespaces() - Service configuration - All four services (frontend, history, matching, worker) need proper port configuration
Configuration from file
For non-SQLite databases, you can load configuration from a YAML file:
cfg, err := config.Load(
config.WithConfigFile("/path/to/config.yaml"),
)
if err != nil {
log.Fatal(err)
}
server, err := temporal.NewServer(
temporal.ForServices(temporal.DefaultServices),
temporal.WithConfig(cfg),
)
Or load from a directory with environment-specific files:
cfg, err := config.Load(
config.WithConfigDir("./config"),
config.WithEnv("development"),
)
Server options reference
The temporal.NewServer() function accepts options to customize the server.
See Server Options Reference for the complete list.
Key options include:
| Option | Description |
|---|---|
ForServices([]string) | Services to run (default: frontend, history, matching, worker) |
WithConfig(*config.Config) | Server configuration |
WithLogger(log.Logger) | Custom logger |
WithAuthorizer(authorization.Authorizer) | Custom authorization |
WithClaimMapper(func) | Role/claim mapping for auth |
WithCustomMetricsHandler(metrics.Handler) | Custom metrics handler |
WithDynamicConfigClient(dynamicconfig.Client) | Runtime configuration |
InterruptOn(chan) | Channel for graceful shutdown |
SQLite limitations
SQLite is intended for testing and development only:
- Single writer: SQLite supports only one writer at a time, limiting write throughput
- No durability in memory mode: In-memory mode loses data on restart
- Not scalable: Cannot handle production workloads
- Single shard: Use
NumHistoryShards: 1for SQLite
For production, use MySQL, PostgreSQL, or Cassandra with a properly scaled multi-node deployment.
Examples
For complete working examples, see:
- Temporal CLI dev server - Reference implementation for SQLite embedding
- samples-server repository - Server extensibility examples:
- Authorizer - Custom authorization and claim mapping
- Metrics handler - Custom metrics handling
- TLS - TLS configuration for secure communication
- Docker Compose - Database configurations (PostgreSQL, MySQL, Cassandra)