# Connection Strings

Connect to your PostgreSQL databases.

Connect to your PostgreSQL databases.

## Getting the Connection String

Get your database connection string from the API:

```bash
curl https://api.volcano.dev/projects/PROJECT_ID/databases/DATABASE_NAME \
  -H "Authorization: Bearer $PLATFORM_TOKEN"
```

**Response:**

```json
{
  "id": "abc-123-456-789",
  "name": "my_app_db",
  "status": "active",
  "connection_string": "postgresql://volcano_client_11111111-1111-1111-1111-111111111111:vpg_abc123@database.volcano.dev:5432/mydb?sslmode=require&application_name=volcano_full_access",
  "region": "us-east-1",
  "pg_version": "18"
}
```

The `connection_string` is only shown when the database status is `active`.

## Connection String Format

Your connection string follows the standard PostgreSQL format:

```text
postgresql://username:password@hostname:port/database
```

**Example:**

```text
postgresql://volcano_client_11111111-1111-1111-1111-111111111111:vpg_abc123@database.volcano.dev:5432/myapp_main?sslmode=require&application_name=volcano_full_access
```

**Components:**

- `username` - Volcano-managed per-database client user (`volcano_client_{database_id}`)
- `password` - Volcano-managed generated password (starts with `vpg_`)
- `hostname` - Volcano pgproxy hostname
- `port` - 5432 (standard PostgreSQL port)
- `database` - Your database name

These are the only credentials the API returns; the internal owner credentials are never exposed and do not authenticate through pgproxy.

## Using in Functions

Volcano doesn't set `DATABASE_URL` (or any variable) automatically. Set it yourself as a project variable using the connection string from `GET /projects/{id}/databases/{databaseName}`:

```bash
curl -X POST https://api.volcano.dev/projects/PROJECT_ID/variables \
  -H "Authorization: Bearer $PLATFORM_TOKEN" \
  -d '{"name":"DATABASE_URL","value":"postgresql://..."}'
```

Then reference it in your function:

```javascript
const { Pool } = require('pg');
const pool = new Pool({
  connectionString: process.env.DATABASE_URL,
});
```

## Direct Connection

You can connect directly using `psql` or any PostgreSQL client:

```bash
# Using psql with connection string
psql "postgresql://volcano_client_11111111-1111-1111-1111-111111111111:vpg_abc123@database.volcano.dev:5432/mydb?sslmode=require&application_name=volcano_full_access"

# Using connection parameters
psql -h database.volcano.dev -p 5432 -U volcano_client_11111111-1111-1111-1111-111111111111 -d mydb
```

When prompted, enter your password (from the connection string).

## Connection Pooling

Recommended for functions:

```javascript
const { Pool } = require('pg');

// Create pool once (outside handler)
const pool = new Pool({
  connectionString: process.env.DATABASE_URL,
  max: 1, // Limit connections per function instance
});

// Reuse in handlers
exports.handler = async (event) => {
  const client = await pool.connect();
  try {
    const result = await client.query('SELECT NOW()');
    return { statusCode: 200, body: JSON.stringify(result.rows) };
  } finally {
    client.release(); // Always release
  }
};
```

## One Statement per Query

Each query you send holds one SQL statement. A query string with several
statements separated by semicolons is refused before any of it runs:

```javascript
await client.query('SELECT 1; SELECT 2');
// error: Multiple statements are not supported
//   code: '0A000'
//   hint: 'Send one statement per query. To apply several together, send them one at a time between BEGIN and COMMIT.'
```

Semicolons inside a single statement are fine, such as in a string literal or a
function body between `$$` quotes.

This mostly affects migration tools that send a whole file as one query. Send
the statements one at a time instead, inside a transaction when they must apply
together:

```javascript
const client = await pool.connect();
try {
  await client.query('BEGIN');
  await client.query('CREATE TABLE posts (id bigserial PRIMARY KEY, title text NOT NULL)');
  await client.query('CREATE INDEX posts_title_idx ON posts (title)');
  await client.query('COMMIT');
} catch (err) {
  await client.query('ROLLBACK');
  throw err;
} finally {
  client.release();
}
```

`psql -f` already sends a file statement by statement. `psql -c` with several
statements does not, and neither do [`volcano` migrations](https://docs.volcano.dev/platform/guides/migrations.md#one-statement-per-file):
each file is one query, so keep one statement per file.

## Security

**SSL/TLS:**
All database connections use SSL/TLS encryption by default for security.

**Keep Credentials Safe:**

> **Warning:**
>
> - Never commit connection strings to git
> - Use environment variables (DATABASE_URL)
> - Rotate passwords if exposed (see Resetting Passwords below)

## Connection Limits

Databases have connection limits based on your plan.

For functions, use:

- Connection pooling (pg.Pool)
- max: 1 connection per function instance
- Always release connections

## Resetting Passwords

If connection string is compromised:

```bash
curl -X POST https://api.volcano.dev/projects/PROJECT_ID/databases/DATABASE_NAME/reset-password \
  -H "Authorization: Bearer $PLATFORM_TOKEN"
```

Rotates the Volcano-managed client password and returns a new connection string. Within a few seconds the old password stops authenticating through pgproxy. Connections already open keep working until they close, so anything still holding the old string has to be pointed at the new one to reconnect. Internal credentials are not reset or exposed.

### Local mode

Call the same path at `http://localhost:8000` with your local platform token. Database connections default to `localhost:8002`.

The printed `app` URL contains its initial password. After resetting `app`, use `connection_string` from the reset response.

## See Also

- [Creating Databases](https://docs.volcano.dev/platform/databases/creating-databases.md)
- [Row-Level Security](https://docs.volcano.dev/platform/databases/row-level-security.md)
