MySQL
Set up Nextly with MySQL. Covers installation, configuration, connection pooling, SSL, Docker setup, and MySQL-specific limitations.
MySQL is supported for teams with existing MySQL infrastructure. The adapter uses the mysql2 driver and handles MySQL-specific differences like the lack of a RETURNING clause automatically.
Installation
Install the MySQL adapter alongside its peer dependency:
@nextlyhq/adapter-mysql mysql2Configuration
Add the adapter to your nextly.config.ts:
import { defineConfig } from '@nextlyhq/nextly';
export default defineConfig({
database: {
adapter: 'mysql',
url: process.env.DATABASE_URL,
},
});Programmatic Usage
You can also create the adapter directly:
import { createMySqlAdapter } from '@nextlyhq/adapter-mysql';
const adapter = createMySqlAdapter({
url: process.env.DATABASE_URL!,
});
await adapter.connect();Connection String
MySQL connection strings follow this format:
mysql://user:password@host:port/databaseFor example:
DATABASE_URL=mysql://nextly:nextly@localhost:3306/nextly_devYou can also specify connection details individually:
export default defineConfig({
database: {
adapter: 'mysql',
host: 'localhost',
port: 3306,
database: 'nextly_dev',
user: 'nextly',
password: 'nextly',
},
});Connection Pool
The adapter uses mysql2's built-in connection pooling. Default settings:
| Option | Default | Description |
|---|---|---|
pool.max | 10 | Maximum connections in the pool. |
pool.idleTimeoutMs | 30000 | Close idle connections after 30 seconds. |
pool.connectionTimeoutMs | 10000 | Timeout when establishing a new connection. |
To customize:
export default defineConfig({
database: {
adapter: 'mysql',
url: process.env.DATABASE_URL,
pool: {
max: 20,
idleTimeoutMs: 30000,
connectionTimeoutMs: 10000,
},
},
});SSL Configuration
For production databases, enable SSL:
export default defineConfig({
database: {
adapter: 'mysql',
url: process.env.DATABASE_URL,
ssl: {
rejectUnauthorized: true,
ca: process.env.CA_CERT,
},
},
});MySQL-Specific Options
These options are unique to the MySQL adapter:
| Option | Type | Default | Description |
|---|---|---|---|
charset | string | utf8mb4 | Character set for the connection. |
timezone | string | 'local' | Timezone for date handling. |
multipleStatements | boolean | false | Allow multiple SQL statements per query. Disabled by default for security. |
dateStrings | boolean | false | Return dates as strings instead of Date objects. |
queryTimeoutMs | number | 15000 | Default timeout for the adapter's executeWithTimeout() method. |
export default defineConfig({
database: {
adapter: 'mysql',
url: process.env.DATABASE_URL,
charset: 'utf8mb4',
timezone: '+00:00',
},
});Differences from PostgreSQL
The MySQL adapter handles several differences automatically, but they are worth knowing:
- No RETURNING clause -- After INSERT and UPDATE operations, the adapter performs an extra SELECT to return the affected rows. This is transparent to your application code.
- No savepoints -- Nested transactions are not supported. Savepoint methods are disabled for safety.
- No ILIKE -- Case-insensitive search uses
LOWER(column) LIKE LOWER(value)as a fallback. This happens automatically when you use theILIKEoperator in your queries. - No JSONB -- MySQL has a native JSON type but lacks PostgreSQL's JSONB with its indexing and operators.
- No array types -- Arrays must be stored as JSON.
- Upsert syntax -- Uses
ON DUPLICATE KEY UPDATEinstead of PostgreSQL'sON CONFLICT DO UPDATE. The adapter handles this transparently. - Backtick identifiers -- MySQL uses backticks for escaping identifiers instead of double quotes.
?placeholders -- MySQL uses?for query parameters instead of$1,$2.
Deadlock Retry
The adapter automatically retries transactions that fail with deadlock errors (MySQL error 1213). Configure retry behavior with transaction options:
await adapter.transaction(
async (tx) => {
await tx.insert('orders', orderData);
await tx.update('inventory', stockUpdate, where);
},
{
retryCount: 3,
retryDelayMs: 100, // Exponential backoff: 100ms, 200ms, 300ms
}
);Docker Setup for Local Development
Run MySQL locally with Docker:
docker run -d --name nextly-mysql \
-e MYSQL_ROOT_PASSWORD=root \
-e MYSQL_USER=nextly \
-e MYSQL_PASSWORD=nextly \
-e MYSQL_DATABASE=nextly_dev \
-p 3306:3306 \
mysql:8Then set your environment variable:
DATABASE_URL=mysql://nextly:nextly@localhost:3306/nextly_devTo stop and remove the container:
docker stop nextly-mysql && docker rm nextly-mysqlCapabilities
The MySQL adapter reports the following capabilities:
{
dialect: 'mysql',
supportsJsonb: false,
supportsJson: true,
supportsArrays: false,
supportsGeneratedColumns: true,
supportsFts: true,
supportsIlike: false,
supportsReturning: false,
supportsSavepoints: false,
supportsOnConflict: true,
maxParamsPerQuery: 65535,
maxIdentifierLength: 64,
}Next Steps
- Database overview -- Compare all supported databases
- Environment Variables -- Database-related environment variables
- Deployment -- Production database and hosting configuration
- PostgreSQL setup -- Recommended for production
- SQLite setup -- Recommended for local development
PostgreSQL
Set up Nextly with PostgreSQL. Covers installation, configuration, connection pooling, SSL, Docker setup, and production recommendations.
SQLite
Set up Nextly with SQLite. Zero-config database for local development and small projects. Covers file path configuration, WAL mode, in-memory databases, and limitations.