Self-hosted REST and GraphQL API for the EVE Online Static Data Export (SDE). It stores SDE data in SQLite, builds an FTS5 search index, and exposes a small API that is easy to run locally, in Docker, or behind your own service.
- Imports CCP's official SDE zip into SQLite.
- Serves item lookup, taxonomy, list, and full-text search endpoints.
- Provides a GraphQL endpoint with GraphiQL enabled.
- Includes API key authentication, admin key management, and rate limiting.
- Stores API keys as SHA-256 hashes at rest; the raw key is only returned once.
- Proxies selected ESI endpoints with retry and in-memory caching.
- Ships with Prometheus metrics and Grafana provisioning.
- Includes a Go SDK under
sdk/go.
- Go 1.25 or newer.
- Docker or Docker Compose if you want containerized deployment.
- About 400 MB of network download for a full SDE import.
git clone https://github.com/ilyaux/eve-sde-server.git
cd eve-sde-server
go mod download
make migrate
go run ./cmd/serverThe server starts on http://localhost:8080.
curl http://localhost:8080/health
curl http://localhost:8080/api/v1/items/34
curl "http://localhost:8080/api/v1/search?q=mineral&limit=5"make migrate creates the SQLite schema and a small sample dataset. For real
data, import the full SDE:
make import-sdedocker compose up --buildThe container initializes the SQLite schema on startup. It does not download the
full SDE automatically; run make import-sde locally or execute
./eve-sde-import-sde inside a container that has the data volume mounted.
Services from docker-compose.yml:
- API server:
http://localhost:8080 - Prometheus:
http://localhost:9090 - Grafana:
http://localhost:3000(admin/admin)
Tagged releases publish a GHCR image:
docker pull ghcr.io/ilyaux/eve-sde-server:v1.0.0
docker run --rm -p 8080:8080 ghcr.io/ilyaux/eve-sde-server:v1.0.0Environment variables:
| Variable | Default | Description |
|---|---|---|
PORT |
8080 |
HTTP port. |
DB_PATH |
data/sde.db |
SQLite database path. |
TLS_ENABLED |
false |
Enables HTTPS. |
TLS_CERT_FILE |
empty | TLS certificate path. |
TLS_KEY_FILE |
empty | TLS private key path. |
ALLOWED_ORIGINS |
* |
Comma-separated CORS origins. |
AUTH_ENABLED |
false |
Enables API key auth for API routes. |
ADMIN_USERNAME |
admin |
Basic auth username for /admin. |
ADMIN_PASSWORD |
admin |
Basic auth password for /admin. |
SDE_AUTO_UPDATE |
false |
Enables scheduled SDE update checks. |
SDE_URL |
CCP SDE URL | SDE zip download URL. |
SDE_DATA_DIR |
data |
Directory used for SDE downloads and extraction. |
CACHE_TTL |
60s |
Response cache TTL, parsed as a Go duration. |
CACHE_MAX_SIZE_MB |
100 |
Maximum in-memory response cache size. |
For public deployments, set explicit ALLOWED_ORIGINS, enable TLS at the edge,
and replace the default admin credentials.
Base URL: http://localhost:8080/api/v1
GET /items?limit=50&offset=0
GET /items/{type_id}
GET /search?q=tritanium&limit=10&offset=0
GET /categories?limit=50&offset=0
GET /categories/{category_id}
GET /categories/{category_id}/groups
GET /groups?category_id=6&limit=50&offset=0
GET /groups/{group_id}
GET /diff?from=20250101&to=20250201
GET /changelogList and search responses use this shape:
{
"data": [
{
"type_id": 34,
"name": "Tritanium",
"description": "A heavy, silver-gray metal...",
"volume": 0.01,
"group_id": 18,
"category_id": 4
}
],
"meta": {
"count": 1,
"total": 1,
"limit": 10,
"offset": 0
}
}OpenAPI documentation is served at http://localhost:8080/docs.
Operational endpoints are public so orchestrators and monitoring systems can check the service without an API key:
GET /health
GET /ready
GET /versionEndpoint: http://localhost:8080/api/graphql
query {
search(query: "shield booster", limit: 5) {
typeId
name
volume
groupId
categoryId
}
groups(categoryId: 6, limit: 5) {
groupId
name
}
}When AUTH_ENABLED=true, REST and GraphQL API requests require an API key:
curl -H "Authorization: Bearer esk_your_api_key" \
http://localhost:8080/api/v1/items/34Admin routes use HTTP Basic Auth:
GET /api/admin/stats
GET /api/admin/keys
POST /api/admin/keys
DELETE /api/admin/keys/{id}
POST /api/admin/sde/update
GET /api/admin/sde/statusThe read-only ESI proxy is public. POST /api/esi/cache/clear is a mutating
maintenance endpoint and requires an API key when AUTH_ENABLED=true.
go get github.com/ilyaux/eve-sde-server/sdk/goclient := evesde.NewClient("http://localhost:8080", "")
item, err := client.GetItem(34)
results, err := client.Search("tritanium", 10)
list, err := client.ListItemsWithMeta(50, 0)
categories, err := client.ListCategories(50, 0)
groups, err := client.ListGroups(6, 50, 0)
changelog, err := client.Changelog()
typeInfo, err := client.ESITypeInfo(34)
ready, err := client.Ready()
version, err := client.Version()go test ./...
go vet ./...
go build -o bin/eve-sde-server ./cmd/serverUseful make targets:
make migrate
make import-sde
make test
make docker-compose-up
make docker-compose-downThe CI workflow runs vet, unit tests, race tests on Linux, SDK checks, server build, and Docker image build.
Contributions are welcome. Start with CONTRIBUTING.md for local setup, quality gates, and pull request expectations.
Please report vulnerabilities privately; see SECURITY.md. Notable changes are tracked in CHANGELOG.md.
Maintainer release notes are in docs/releasing.md.
cmd/ command binaries
internal/api/ HTTP handlers and middleware
internal/auth/ API key management
internal/cache/ memory and Redis cache implementations
internal/database/ SQLite setup and migrations
internal/graphql/ GraphQL schema and resolvers
internal/sde/ SDE downloader, parser, and importer
internal/scheduler/ scheduled SDE updates
sdk/go/ Go SDK
api/openapi.yaml OpenAPI spec
deployments/ Prometheus and Grafana provisioning
web/ Swagger and admin HTML
MIT. See LICENSE.