Environments
Environments let you group related database connections and CI repos under a single named entity — typically representing a service or application. This makes it easy to manage multiple services that each have their own database and CI pipeline.
Concepts
Section titled “Concepts”An environment has:
- Name — a human-readable label (e.g. “Billing Service”)
- Slug — a URL-safe identifier (e.g.
billing-service), lowercase alphanumeric with hyphens - Database connections — PostgreSQL connection strings, each with a role (
production,staging,ci, orother) - Linked repos — GitHub repositories whose CI runs belong to this environment
- Query catalog — a persistent inventory of every unique SQL query seen across CI runs, built automatically as runs are ingested
When a CI repo is linked to an environment, new CI runs from that repo are automatically associated with the environment and their queries are added to the catalog.
Creating an environment
Section titled “Creating an environment”Via the UI
Section titled “Via the UI”- Navigate to
/environmentsin the app. - Click New Environment.
- Enter a Name and Slug.
- The slug must be lowercase letters, numbers, and hyphens only (e.g.
billing-service).
- The slug must be lowercase letters, numbers, and hyphens only (e.g.
- Click Create.
Via the API
Section titled “Via the API”curl -X POST https://api.querydoctor.com/env \ -H 'Content-Type: application/json' \ -d '{"name": "Billing Service", "slug": "billing-service"}'Returns { "id": "<environment-id>" }.
Adding database connections
Section titled “Adding database connections”Each connection has a role that describes its purpose:
| Role | Description |
|---|---|
production | The production database. Used as the source of query planner statistics for analyzing queries from other databases. |
staging | A staging or pre-production database. |
ci | The database used by CI test runs. |
other | Any other database (default). |
Via the UI
Section titled “Via the UI”- Go to
/environments/<id>(click an environment from the list). - Under Database Connections, fill in a Label, select a Role, and enter the Connection string.
- Click Add Connection.
Via the API
Section titled “Via the API”curl -X POST https://api.querydoctor.com/env/<id>/connections \ -H 'Content-Type: application/json' \ -d '{"label": "Production", "role": "production", "connectionString": "postgres://user:pass@host:5432/billing"}'Returns { "id": "<connection-id>" }.
To remove a connection:
curl -X DELETE https://api.querydoctor.com/env/<id>/connections/<connection-id>Linking CI repos
Section titled “Linking CI repos”Linking a repo to an environment associates that repo’s CI runs with the environment. This lets you view all CI data for a service in one place.
The repo identifier should match the format used by the analyzer action: org/repo (e.g. query-doctor/billing-api).
Via the UI
Section titled “Via the UI”- Go to
/environments/<id>. - Under Linked Repos, enter the repo in
org/repoformat. - Click Link Repo.
Via the API
Section titled “Via the API”curl -X POST https://api.querydoctor.com/env/<id>/repos \ -H 'Content-Type: application/json' \ -d '{"repo": "query-doctor/billing-api"}'Returns { "id": "<repo-link-id>" }.
To unlink a repo:
curl -X DELETE https://api.querydoctor.com/env/<id>/repos/query-doctor%2Fbilling-apiNote the URL-encoded / (%2F) in the repo path.
Managing environments
Section titled “Managing environments”Updating
Section titled “Updating”curl -X PATCH https://api.querydoctor.com/env/<id> \ -H 'Content-Type: application/json' \ -d '{"name": "Billing Service (v2)"}'Both name and slug can be updated. Both fields are optional — only include the ones you want to change.
Deleting
Section titled “Deleting”Via the UI, click the Delete Environment button on the environment detail page and confirm.
Via the API:
curl -X DELETE https://api.querydoctor.com/env/<id>Listing
Section titled “Listing”curl https://api.querydoctor.com/envReturns an array of { id, name, slug, createdAt } objects.
Getting details
Section titled “Getting details”curl https://api.querydoctor.com/env/<id>Returns the environment with its connections and linked repos:
{ "id": "abc123", "name": "Billing Service", "slug": "billing-service", "createdAt": "2026-03-06T00:00:00.000Z", "connections": [ { "id": "conn1", "label": "Production", "role": "production", "createdAt": "..." } ], "repos": [ { "id": "repo1", "repo": "query-doctor/billing-api", "createdAt": "..." } ]}Query catalog
Section titled “Query catalog”Once a CI repo is linked and CI runs are ingested, the environment automatically builds a query catalog — a persistent inventory of every unique SQL query seen across CI runs.
What you see
Section titled “What you see”On the environment detail page (/environments/<id>), the Query Catalog section shows a table with:
| Column | Description |
|---|---|
| Query | The formatted SQL (fingerprinted, so parameters are normalized) |
| Source | Where the query was last seen (ci, production, or manual) |
| CI Runs | How many CI runs have included this query |
| Last Seen | When the query was most recently observed |
Queries are sorted by most recently seen first. The catalog grows automatically as new CI runs are ingested — no manual action is needed.
How it works
Section titled “How it works”Each CI run contains a list of queries with their fingerprint hashes. When a run is ingested:
- New queries are added to the catalog
- Existing queries (matched by hash) have their
lastSeenAtandciRunCountupdated - The formatted query text is kept up to date
Query catalog API
Section titled “Query catalog API”List all queries for an environment:
curl https://api.querydoctor.com/env/<id>/queriesReturns an array of:
[ { "id": "...", "hash": "abc123def", "formattedQuery": "SELECT id, name FROM users WHERE email = $1", "firstSeenAt": "2026-03-01T00:00:00.000Z", "lastSeenAt": "2026-03-07T00:00:00.000Z", "lastSeenSource": "ci", "ciRunCount": 12 }]Get a single query by hash:
curl https://api.querydoctor.com/env/<id>/queries/<hash>Returns the full query record including query (raw SQL), createdAt, and updatedAt.
CI runs and environments
Section titled “CI runs and environments”When a CI repo is linked to an environment, CI runs from that repo are tagged with the environment. On the CI Runs page (/ci), each run shows the environment name as a badge next to the repo name, making it easy to see which environment a run belongs to.
Example: setting up a service
Section titled “Example: setting up a service”Here’s a typical workflow for onboarding a new service:
-
Create the environment:
- Name: “User Service”, Slug:
user-service
- Name: “User Service”, Slug:
-
Add database connections:
- Label: “Production”, Role:
production, Connection:postgres://...prod-host.../users - Label: “Staging”, Role:
staging, Connection:postgres://...staging-host.../users
- Label: “Production”, Role:
-
Link the CI repo:
- Repo:
my-org/user-service
- Repo:
-
Set up CI integration:
- Follow the CI Integration guide to add the analyzer action to your repo’s workflow. CI runs will automatically associate with this environment.
-
Review your query catalog:
- After a few CI runs, visit the environment detail page. The Query Catalog will show all unique queries discovered by CI, along with how often each appears.