| 1 | --- |
| 2 | title: MySQL |
| 3 | description: Official MySQL in a Project. Bind Railway.ConnectMySQL and query with Drizzle or SQL. |
| 4 | --- |
| 5 | |
| 6 | A [`Railway.MySQL`](/providers/railway/mysql) is MySQL as a Service: |
| 7 | the official `mysql:9` image, a Volume at `/var/lib/mysql`, `MYSQL_*` |
| 8 | / `MYSQL_URL` variables, and an optional TCP proxy for the public URL. |
| 9 | The IaC helper is `Railway.mysql`. |
| 10 | |
| 11 | Private hostname is `{name}.railway.internal`. From a |
| 12 | [Service](/railway/compute/services), yield |
| 13 | [`ConnectMySQL`](/providers/railway/connectmysql). From a laptop, use |
| 14 | `publicConnectionUri`. |
| 15 | |
| 16 | ## Create MySQL |
| 17 | |
| 18 | Pass a Project. Alchemy generates a unique name, password, volume, |
| 19 | and a public TCP proxy. |
| 20 | |
| 21 | ```typescript |
| 22 | const site = yield* Railway.Project("Site"); |
| 23 | const db = yield* Railway.MySQL("Db", { project: site }); |
| 24 | ``` |
| 25 | |
| 26 | :::caution[Changing `project` replaces MySQL] |
| 27 | A new service + volume are created in the new Project. The old |
| 28 | service and volume are deleted. Data is not copied. |
| 29 | ::: |
| 30 | |
| 31 | ## Connect from a Service |
| 32 | |
| 33 | Yield `ConnectMySQL` in the Service's constructor. Provide |
| 34 | `ConnectMySQLHttp`. Pass `conn.connectionString` to Drizzle or SQL. |
| 35 | |
| 36 | ```typescript |
| 37 | import * as Drizzle from "alchemy/Drizzle/MySQL"; |
| 38 | import * as HttpServerResponse from "effect/http/HttpServerResponse"; |
| 39 | |
| 40 | export default class Api extends Railway.Service<Api>()( |
| 41 | "Api", |
| 42 | { |
| 43 | project: Site, |
| 44 | main: import.meta.url, |
| 45 | build: { install: ["mysql2"] }, |
| 46 | }, |
| 47 | Effect.gen(function* () { |
| 48 | const conn = yield* Railway.ConnectMySQL(Db); |
| 49 | const db = yield* Drizzle.MySQL(conn.connectionString); |
| 50 | return { |
| 51 | fetch: Effect.gen(function* () { |
| 52 | const rows = yield* db.execute("select 1 as ok", "objects"); |
| 53 | return HttpServerResponse.json({ rows }); |
| 54 | }), |
| 55 | }; |
| 56 | }).pipe(Effect.provide(Railway.ConnectMySQLHttp)), |
| 57 | ) {} |
| 58 | ``` |
| 59 | |
| 60 | `connectionString` is the private URI |
| 61 | (`{name}.railway.internal:3306`). Packed into the Service env — not |
| 62 | `Config.Redacted`. |
| 63 | |
| 64 | To store Railway's `${{Db.MYSQL_URL}}` template instead of a |
| 65 | resolved URI, pass [`Railway.ref`](/providers/railway/ref) |
| 66 | (`Railway.ref(Db, "MYSQL_URL")`) as a |
| 67 | [Variable](/railway/data/variables) `value`. |
| 68 | |
| 69 | ## Public TCP |
| 70 | |
| 71 | `public` (default `true`) creates a TCP proxy on 3306. |
| 72 | `publicConnectionUri` is `{domain}:{proxyPort}` for laptop access. |
| 73 | |
| 74 | ```typescript |
| 75 | const db = yield* Railway.MySQL("Db", { |
| 76 | project: site, |
| 77 | public: false, |
| 78 | }); |
| 79 | ``` |
| 80 | |
| 81 | ## Where next |
| 82 | |
| 83 | [Postgres](/railway/data/postgres) is the same shape for Postgres. |
| 84 | [Mongo](/railway/data/mongo) is MongoDB. |
| 85 | [TcpProxy](/railway/networking#tcp-proxies) is the public TCP |
| 86 | resource. |
| 87 | The [`MySQL` reference](/providers/railway/mysql) lists every prop. |
| 88 | The [`ConnectMySQL` reference](/providers/railway/connectmysql) is |
| 89 | the runtime binding. |