All notes
SQL & Database3 min readUpdated August 7, 2026

Connecting an Application to a Database

From the connection string to the choice between an ORM and raw queries, plus two things that cannot be skipped: credentials that do not leak, and queries that cannot be injected into.

DatabaseConnectionORMSQL InjectionConnection PoolLaravelNext.js

Connecting an application to a database always consists of the same parts, whatever the language: the server address, the database name, credentials, and a driver that translates the application's commands into a protocol the database understands.

Configuration lives in the environment, not the code

Credentials go in environment variables so their values can differ between a laptop, staging and production without changing a line of code. The .env file never enters Git — only .env.example does, listing the variable names with no values.

The shape is much the same everywhere
# Laravel — .env
DB_CONNECTION=pgsql
DB_HOST=127.0.0.1
DB_PORT=5432
DB_DATABASE=vms
DB_USERNAME=vms_app
DB_PASSWORD=…

# Node / Next.js — .env.local
DATABASE_URL=postgresql://vms_app:…@127.0.0.1:5432/vms

Connection pooling

Opening a connection is expensive, so an application keeps a set of open connections to be used in turn. The number is finite — when they are all in use, the next request waits. This is a common reason an application suddenly slows under load while the queries themselves are fast: the query is not slow, it is queuing for a connection.

ORM, query builder, or raw SQL

ApproachStrengthSuits
ORM (Eloquent, Prisma)Concise, relations are easy, safe from injection by defaultEveryday CRUD
Query builderStill reads as code, but sits closer to SQLQueries with dynamic conditions
Raw SQLFull control, can use database-specific featuresReports and complex aggregation

All three can coexist in one application. A healthy pattern: an ORM for ordinary operations, raw SQL for the reports that are genuinely awkward to express through it.

Never build a query by concatenating strings

Inserting user input straight into query text makes that input readable as a command. This is SQL injection. The defence is not filtering strange characters but using bound parameters — the database receives the query and the values separately, so a value can never be treated as a command.

-- Dangerous: the input becomes part of the command
"SELECT * FROM users WHERE email = '" + email + "'"
-- input: ' OR '1'='1  →  every row comes back

-- Safe: the value is sent separately from the command
SELECT * FROM users WHERE email = ?

Before calling it done

  1. 01Use a dedicated application database user with only the rights it needs — not a superuser account.
  2. 02Set timeouts, so a stuck query does not hold a connection forever.
  3. 03Handle connection failure with a clear message; databases are occasionally unreachable.
  4. 04Make sure the error text reaching users carries no database structure detail.
  5. 05Test the restore path, not just the backup process.

More notes