---
title: "Connect a database that stays where it is (Neon, Supabase, PlanetScale, Upstash, MongoDB Atlas, …) to a project: the URL is checked (public addresses only), tested once and stored only as the project's encrypted variables (DATABASE_URL and the usual framework names)"
method: POST
path: "/projects/{projectId}/databases/external"
tags: ["Databases"]
---

# Connect a database that stays where it is (Neon, Supabase, PlanetScale, Upstash, MongoDB Atlas, …) to a project: the URL is checked (public addresses only), tested once and stored only as the project's encrypted variables (DATABASE_URL and the usual framework names)

`POST /projects/{projectId}/databases/external`

## Request

- Base URL: `https://hostingsurge.com/api/v1`
- URL: `https://hostingsurge.com/api/v1/projects/{projectId}/databases/external`
- Auth: one of:
  - HTTP bearer
  - API key in cookie `__Host-hs_session`

## Path parameters

- `projectId` string, uuid, required

## Request body

- object
  - `url` string, required: Connection URL with credentials: postgresql://, postgres://, mysql://, mariadb://, mongodb://, mongodb+srv://, redis:// or rediss://. Stored only as the project's encrypted variables; never returned or logged
  - `tls` 'prefer' | 'require' | 'verify-full' | 'disable': TLS for the test: prefer (default), require, verify-full or disable; the app follows the URL's own options
  - `conventions` boolean: true (default): every name the usual frameworks read (PostgreSQL: DATABASE_URL, DATABASE_URL_UNPOOLED, POSTGRES_URL, POSTGRES_PRISMA_URL, POSTGRES_URL_NON_POOLING, POSTGRES_HOST/USER/PASSWORD/DATABASE and PG*; MySQL: DATABASE_URL, MYSQL_URL and MYSQL_*; MongoDB: MONGODB_URI, MONGO_URL, DATABASE_URL; Redis: REDIS_URL, KV_URL). false: envKey alone
  - `envKey` string: the main variable (default DATABASE_URL, MONGODB_URI for MongoDB, REDIS_URL for Redis)
  - `test` boolean: false saves without the connection test (e.g. a firewall that only lets the app's server in)
  - `overwrite` boolean: replace variables of those names that the project already has (otherwise 409 conflict with their names)
  - `redeploy` boolean: deploy the project again so the running app gets the variables

## Response `200`

Connected, or the test failed and nothing was saved (state test_failed)

- object
  - `state` 'connected' | 'test_failed', required: test_failed: nothing was saved; fix what the message says, or save with test: false
  - `engine` 'postgresql' | 'mysql' | 'mariadb' | 'mongodb' | 'redis', required
  - `host` string, required: the server, without credentials
  - `variables` string[], required: the names written (connected) or that would be written (test_failed)
  - `test` object, required: signed_in: the credentials were accepted (PostgreSQL, Redis); reachable: a server of that engine answered and the app signs in itself (MySQL, MariaDB, MongoDB)
    - `level` 'signed_in' | 'reachable' | 'failed' | 'skipped', required
    - `message` string, required
    - `serverVersion` string, nullable, required
    - `latencyMs` integer, nullable, required
  - `deploymentId` string, uuid, nullable, required: redeploy: the new deployment

## Other responses

- `400`: Invalid request (code invalid_request)
- `401`: Missing or invalid session/token (code unauthorized)
- `403`: Authenticated but not permitted (code forbidden)
- `404`: Not found or not visible to the caller (code not_found)
- `409`: Conflicting state (code conflict)
- `429`: Too many requests (code rate_limited); see Retry-After
- `501`: Not available on this server (code not_configured)
- `503`: Hosting engine unavailable (code provider_unavailable)

---

[API](https://skmtc.dev/hostingsurge/apis/hostingsurge-platform-api.md) · [All operations](https://skmtc.dev/hostingsurge/apis/hostingsurge-platform-api/llms.txt) · [OpenAPI document](https://skmtc.dev/hostingsurge/apis/hostingsurge-platform-api/revisions/4d08337cdff1?raw)
