Skip to content

Admin Console

AWSim includes a SvelteKit-based web UI for browsing and managing emulated resources.

Running the UI

The UI lives in the ui/ directory of the repository:

bash
cd ui
bun install
bun run dev

The dev server starts on http://localhost:5173 by default. It proxies /_awsim requests to AWSim running on http://localhost:4566, so make sure AWSim is running before opening the UI.

Admin API Endpoints

AWSim exposes a lightweight admin API independent of the AWS wire protocol:

EndpointMethodDescription
/_awsim/healthGETHealth check — returns {"status":"ok"}
/_awsim/servicesGETList all registered services with their signing names and protocols
/_awsim/configGETActive configuration (port, region, account ID, data-dir)
/_awsim/statsGETRuntime statistics
/_awsim/storageGETPer-service BodyStore disk usage (when --data-dir is set)
/_awsim/storage/sqliteGETPer-service SQLite store row counts + database file sizes (DynamoDB, CloudWatch Logs, CloudWatch Metrics, Kinesis, SES)
/_awsim/eventsGETServer-Sent Events stream of every gateway request
/_awsim/requestsGETMost recent captured request ids (newest first)
/_awsim/requests/{id}GETFull captured detail for one request — headers + bodies
/_awsim/requests/{id}/replayPOSTRe-issue the captured request through the gateway
/_awsim/billingGETRolling estimated AWS bill — running cost, projected monthly, per-service breakdown. See the Billing guide.
/_awsim/debug/objectsGETMemory diagnostic — process RSS plus per-subsystem object counts. See Observability below.
/_awsim/ses/sentGETList every captured outbound email (newest first). Optional ?account= and ?region= filters. See the SES service doc.
/_awsim/admin/dynamodb/vacuumPOSTReclaim disk space in the DynamoDB SQLite store after heavy DELETE / UPDATE churn.
/_awsim/snapshotsGETList saved named snapshots (see Persistence).
/_awsim/snapshots/{name}POST / DELETESave / delete a named snapshot bundle.
/_awsim/snapshots/{name}/loadPOSTRestore a previously saved snapshot.
/_awsim/chaos/rulesGET / POSTList or append chaos-injection rules.
/_awsim/chaos/rules/{id}DELETERemove a chaos rule.
/_awsim/chaos/presets/{name}POSTApply a built-in chaos preset (s3-flaky, ddb-throttled, etc). See the Chaos guide.
/_awsim/seed/cognito-usersPOSTBulk-seed N users into a Cognito user pool. See Seeding.
/_awsim/seed/dynamodbPOSTBulk-seed N tables × M items.
/_awsim/seed/s3POSTBulk-seed N buckets × M small objects.
/_awsim/seed/secretsPOSTBulk-seed N secrets with credential-shaped JSON bodies.
/_awsim/seed/sqsPOSTBulk-seed N queues × M messages.

Example:

bash
curl http://localhost:4566/_awsim/health
curl http://localhost:4566/_awsim/services
curl http://localhost:4566/_awsim/config
curl http://localhost:4566/_awsim/stats
curl http://localhost:4566/_awsim/storage
curl -N http://localhost:4566/_awsim/events
curl http://localhost:4566/_awsim/requests
curl http://localhost:4566/_awsim/requests/<id>
curl -X POST http://localhost:4566/_awsim/requests/<id>/replay

/_awsim/storage

Reports on-disk byte counts for each service that has a BodyStore enabled. When AWSim is started without --data-dir, data_dir is null and the services array is empty.

json
{
  "data_dir": "/var/awsim/data",
  "snapshots": {
    "path": "/var/awsim/data/snapshots",
    "size_bytes": 12345
  },
  "services": [
    {
      "name": "s3",
      "groups": ["objects", "multipart"],
      "size_bytes": 1048576,
      "blob_count": 42
    },
    {
      "name": "lambda",
      "groups": ["lambda"],
      "size_bytes": 512000,
      "blob_count": 3
    },
    {
      "name": "ecr",
      "groups": ["ecr"],
      "size_bytes": 0,
      "blob_count": 0
    },
    {
      "name": "sqs",
      "groups": ["sqs"],
      "size_bytes": 256,
      "blob_count": 12
    }
  ],
  "total_size_bytes": 1573577
}

The handler walks each group directory using metadata() only (no file reads), so it returns quickly even with thousands of files.

/_awsim/events

Opens a Server-Sent Events stream that emits one JSON-encoded event for every AWS API request that flows through the gateway. The connection stays open and pushes events in real time until the client disconnects.

The broadcast channel has a capacity of 256 events; if a slow consumer falls behind, the oldest events are dropped.

Event shape:

json
{
  "id": "req-uuid",
  "ts": 1735041600.123,
  "method": "POST",
  "path": "/",
  "service": "s3",
  "operation": "PutObject",
  "account_id": "000000000000",
  "region": "us-east-1",
  "principal_arn": "arn:aws:iam::000000000000:access-key/AKIA...",
  "status_code": 200,
  "duration_ms": 12.5,
  "request_size": 1024,
  "response_size": 256,
  "error_code": null
}

error_code is null for 2xx/3xx responses and the AWS error code (e.g., "AccessDenied", "NoSuchBucket") when status_code >= 400. principal_arn is null for unauthenticated requests; operation is null only when the request failed before the operation could be parsed.

Each event arrives over the wire as:

data: {"id":"...","ts":1735041600.123,"method":"POST","path":"/","service":"s3","operation":"PutObject","status_code":200,...}

The UI consumes this stream to power the dashboard activity feed and the live request log.

/_awsim/requests, /_awsim/requests/{id}, /_awsim/requests/{id}/replay

Every request that flows through the gateway is also captured into a bounded ring buffer (default 200 entries) keyed by request id. The buffer stores method, path, query, status, both header sets and both bodies. Bodies are size-capped at 64 KiB each direction and stored base64-encoded so binary payloads (S3 objects, ECR layers) survive.

bash
# List the 50 most recent captured ids (newest first)
curl http://localhost:4566/_awsim/requests
# {"ids": ["a1b2...", "c3d4...", ...]}

# Fetch full detail for one request
curl http://localhost:4566/_awsim/requests/a1b2...

POST /_awsim/requests/{id}/replay reconstructs the original request from the captured detail and dispatches it through the gateway again. Returns the freshly minted request id so callers can pull the new detail:

bash
curl -X POST http://localhost:4566/_awsim/requests/a1b2.../replay
# {"new_id": "z9y8...", "status_code": 200, "original_id": "a1b2..."}

Replay returns 409 RequestBodyTruncated when the original request body exceeded the capture cap — partial-body replay would silently lie about the result.

Dashboard

The main dashboard composes a live overview of the running emulator:

  • KPI strip — total requests since boot, live RPS over a trailing 5s window, on-disk usage across BodyStores, and uptime.
  • Live request stream — auto-tailing table of recent requests, filterable by 4xx / 5xx. Click any row to open the inspect drawer.
  • Service status list — per-service blob counts and disk usage from /_awsim/storage.
  • Insights panel — config + BodyStore + SQLite-store summary (top service by row count, total bytes on disk).

Observability

Open /observability from Admin → Observability in the sidebar. It polls /_awsim/debug/objects every 5 s and renders:

  • Process — current RSS plus VmHWM (peak), VmSize, VmData, VmPeak, with a 60-sample RSS sparkline below.
  • Gateway / app — request-details ring size, SSE subscriber counts (catches leaked subscribers), chaos rule + recent injection counts, registered services, uptime.
  • Cognito — user-pool count, mfa-sessions, totals across all pools, plus a per-pool breakdown table (users, groups, clients, auth events, devices, revoked refresh tokens).
  • Billing meter — account-region buckets and total op-counter / storage / compute / resource rows.
  • SQLite-backed stores — row counts per service plus the DynamoDB DB file size.

Hit Snapshot baseline to capture the current values; subsequent renders show signed deltas next to every cell so a leak shows up as a stream of orange +N annotations against the structure that's growing. See the Memory + diagnostics guide.

Seeding

The /_awsim/seed/<service> endpoints fill services with realistic fake data, skipping SigV4 + the gateway so a 10k-row seed completes in well under a second. Three ways to drive them:

bash
# 1. UI: Admin → Seed data — service cards with count inputs + Run buttons.

# 2. curl directly:
curl -XPOST http://localhost:4566/_awsim/seed/cognito-users \
  -d '{"pool_id":"us-east-1_abc","count":10000}'
curl -XPOST http://localhost:4566/_awsim/seed/dynamodb \
  -d '{"tables":5,"items_per_table":1000}'

# 3. Repeatable scenario file (CI-friendly):
awsim seed --file ci-fixtures.toml

Per-call caps to keep the writer responsive:

EndpointCap
cognito-users100 000 users / call
dynamodb1 000 tables / 100 000 items per table
s3500 buckets / 10 000 objects per bucket / 64 KiB body
secrets50 000 / call
sqs1 000 queues / 100 000 messages per queue

TOML scenario shape:

toml
endpoint = "http://localhost:4566"   # optional

[[cognito_users]]
pool_id = "us-east-1_abcdef"
count   = 1000

[dynamodb]
tables          = 5
items_per_table = 1000

[s3]
buckets             = 5
objects_per_bucket  = 100
body_bytes          = 256

[secrets]
count = 20

[sqs]
queues             = 5
messages_per_queue = 50

Service Pages

The UI ships a service-specific page for every backend that AWSim emulates. Each one is built on a shared ServicePage shell with viewport-bound scrolling, a typed API client, and decomposed sub-components (list, detail panels, create dialogs). Examples:

  • S3: Browse buckets, list objects, upload/download
  • DynamoDB: View tables, scan items, run queries
  • SQS: List queues, send and receive messages
  • Lambda: List functions, invoke them
  • Cognito: Pool list at /cognito, full per-pool dashboard at /cognito/[poolId] with a left-nav covering Users (Prev/Next pagination + server-side filter + CSV import), Groups, App clients, Domain, Triggers (Lambda integration editor), Policies (password policy + MFA + tags), Federation (identity providers + resource servers), Appearance (UI customization). See the Cognito service doc.
  • SES: Identity / template / config-set management + an Outbox tab listing every captured outbound email with sandboxed-HTML preview. See the SES service doc.
  • IAM: Manage users, roles, policies, access keys
  • Step Functions: View state machines, executions, execution history (ASL viewer included)
  • Observability (admin): Live RSS sparkline + per-subsystem counts with snapshot/diff. Detailed above.
  • Seed data (admin): Service cards with count inputs to bulk-fill via the seed admin endpoints.

Keyboard Shortcuts

The console is keyboard-first. Press ? any time to bring up the cheat sheet.

General

KeysAction
?Open the shortcut cheat sheet
/Open the command palette (also ⌘K / Ctrl+K)
tToggle dark / light theme (preserves the active dark variant)
[Collapse / expand the sidebar
iInspect the most recent captured request

Navigation — type the leader key g, then a target letter:

SequencePage
g dDashboard
g rRequest log
g sS3
g fLambda (function)
g tDynamoDB (table)
g iIAM
g qSQS (queue)
g nSNS
g kKMS (key)
g eEC2
g cCognito
g mCloudWatch metrics
g xCloudTrail
g wCloudWatch logs
g bBedrock
g pAPI Gateway

A small "leader" chip appears at the bottom of the screen while a sequence is in flight. Esc cancels.

Shortcuts are ignored while typing into inputs, textareas, selects, contenteditable elements, and the command palette input — so they never compete with normal typing.

Inspect Drawer

The Inspect drawer is a global side-panel that loads the captured detail for any request and shows it in a tabbed view:

  • Request — every captured header plus the request body, decoded by content-type. JSON is pretty-printed; XML and form payloads are shown verbatim; non-UTF-8 binary bodies fall back to a hex dump of the first 256 bytes.
  • Response — same treatment for the response side.
  • curl — a runnable curl invocation that reproduces the request against the local emulator, headers and body included.

The drawer header shows the HTTP method, the captured URL, and a Replay button. Clicking Replay re-issues the request through the gateway, swaps the drawer to the freshly captured detail, and toasts the new status code. The button is disabled with an explanatory tooltip when the original body was truncated during capture.

The drawer can be opened from:

  • Any row in the live request stream or request log.
  • The i keyboard shortcut (inspects the most recent request).
  • The "Tools → Inspect last request" entry in the command palette.

Themes

The theme picker on the topbar (and in the command palette's "Theme" group) offers five built-in variants:

VariantNotes
Default DarkNeutral charcoal with the warm AWS-amber accent.
MidnightDeep blue-purple ground with an electric violet accent.
SlateCooler, less saturated dark with a muted blue accent.
Solarized DarkEthan Schoonover's classic palette — warm dark cyan ground, yellow accent.
LightThe default light scheme — full token coverage, usable but not the primary mode.

Each variant is applied as a CSS class composed on top of the existing Tailwind dark class, so any component that uses dark: utilities continues to work. The active theme is persisted in localStorage (awsim-theme), and the pre-paint script in app.html applies it before first paint to avoid a flash of the wrong palette.

Pressing t toggles between dark and light while remembering the most recent dark variant — so a quick t t round-trip never costs you your customised dark.

Notes

  • The UI is a development tool only — it is not packaged inside the AWSim binary.
  • The UI connects to whichever AWSim instance is running on localhost:4566. To point it at a different host/port, set the VITE_AWSIM_URL environment variable before running bun run dev.

Released under MIT / Apache-2.0 License