Project Setup

Prisma Fundamentals

Chapter 2 · Project Setup

This chapter builds a working Prisma 7 project from an empty folder: a TypeScript project, the Prisma packages, the schema, the configuration file, a first table, and a small script that writes and reads a row. It uses SQLite, so there's no database server to install. Every later chapter starts from this project.

Pin the version: plain "npm install prisma" now gets Prisma 8
On the npm registry, the latest tag for the prisma package currently points to a Prisma 8 release candidate (Chapter 1). Installing it without a version gives you Prisma 8, which is set up differently. This course pins every Prisma package to version 7 with @7.

Step 1: Create a TypeScript Project

You'll need Node.js 20.19 or later (22 is recommended).

mkdir prisma-blog && cd prisma-blog npm init -y npm install --save-dev typescript tsx @types/node

tsx runs TypeScript files directly, without a separate compile step. Prisma 7 is published as ES modules, so tell Node your project uses them too, in package.json:

{ "name": "prisma-blog", "type": "module", ... }

And create tsconfig.json:

{ "compilerOptions": { "module": "ESNext", "moduleResolution": "bundler", "target": "ES2023", "strict": true, "esModuleInterop": true } }

Step 2: Install Prisma

# The CLI, used only during development npm install --save-dev prisma@7 @types/better-sqlite3 # What your application uses at run time npm install @prisma/client@7 @prisma/adapter-better-sqlite3@7 dotenv
PackageRole
prismaThe command-line tool: init, migrate, generate, studio
@prisma/clientThe runtime library the generated client is built on
@prisma/adapter-better-sqlite3The driver adapter that connects Prisma to SQLite through the better-sqlite3 driver
dotenvLoads settings such as the database URL from a .env file

Step 3: Initialise Prisma

npx prisma init --datasource-provider sqlite --output ../generated/prisma

This creates three things:

prisma-blog/ ├── prisma/ │ └── schema.prisma # your data model (Chapter 3) ├── prisma7.config.ts # Prisma's settings ├── .env # the database URL ├── package.json └── tsconfig.json
Why "prisma7.config.ts"?
From Prisma 7.10, the configuration file is named prisma7.config.ts, so that it doesn't clash with Prisma 8's prisma.config.ts, which uses a different format. Earlier Prisma 7 releases, and many guides, call it prisma.config.ts. Use whichever name your prisma init creates.

The schema

// prisma/schema.prisma generator client { provider = "prisma-client" output = "../generated/prisma" } datasource db { provider = "sqlite" }
  • The generator block says what to generate. prisma-client is Prisma 7's new client generator; output is where the generated code goes, relative to the schema file. In Prisma 7 the output path is required.
  • The datasource block says which kind of database you're using. The connection details don't go here any more.

The configuration file and .env

// prisma7.config.ts import "dotenv/config"; import { defineConfig } from "prisma/config"; export default defineConfig({ schema: "prisma/schema.prisma", migrations: { path: "prisma/migrations", }, datasource: { url: process.env["DATABASE_URL"], }, });
# .env DATABASE_URL="file:./dev.db"

The config file tells the Prisma CLI where the schema and migrations live and how to reach the database. The import "dotenv/config" line matters: Prisma 7 doesn't load .env by itself, so without it DATABASE_URL would be empty.

Keep .env out of version control
.env will hold real database passwords once you move beyond SQLite. Add .env, the generated client folder, and your SQLite database file to .gitignore.

Step 4: Add a Model and Create the Table

Add a first model to the schema (Chapter 3 explains every part):

model User { id Int @id @default(autoincrement()) email String @unique name String? }
# Create the database table (Chapter 4 explains migrations) npx prisma migrate dev --name init # Generate the type-safe client into generated/prisma npx prisma generate
Generate after every schema change
The client is generated code. Whenever you change schema.prisma, run prisma generate again, or your TypeScript types will describe the old schema.

Step 5: Create the Client and Use It

Put the client in one shared file, so the whole application uses a single instance:

// lib/prisma.ts import "dotenv/config"; import { PrismaBetterSqlite3 } from "@prisma/adapter-better-sqlite3"; import { PrismaClient } from "../generated/prisma/client"; const adapter = new PrismaBetterSqlite3({ url: process.env.DATABASE_URL! }); export const prisma = new PrismaClient({ adapter });

Notice the import path: the client comes from your own generated/prisma folder, not from @prisma/client as in older versions. Now a first script:

// script.ts import { prisma } from "./lib/prisma"; const user = await prisma.user.create({ data: { email: "ada@example.com", name: "Ada" }, }); console.log("Created:", user); const all = await prisma.user.findMany(); console.log("All users:", all); await prisma.$disconnect();
$ npx tsx script.ts Created: { id: 1, email: 'ada@example.com', name: 'Ada' } All users: [ { id: 1, email: 'ada@example.com', name: 'Ada' } ]

Run it a second time and it fails, because email is @unique and Ada already exists. That's the database protecting your data, and Chapter 5 shows how to handle it.

Using PostgreSQL Instead

The structure is the same for other databases; only the provider, the URL, and the adapter change. For PostgreSQL, install the pg driver and its adapter, and change three things:

npm install @prisma/adapter-pg@7 pg // schema.prisma datasource db { provider = "postgresql" } # .env DATABASE_URL="postgresql://user:password@localhost:5432/blog" // lib/prisma.ts import { PrismaPg } from "@prisma/adapter-pg"; const adapter = new PrismaPg({ connectionString: process.env.DATABASE_URL! });

Hands-On Exercises

Exercise 1

Build the project in this chapter from scratch and run script.ts successfully. Then check which Prisma versions were actually installed, and explain why that check matters right now.

📄 View solution
Exercise 2

Remove the import "dotenv/config" line from the config file and run npx prisma migrate dev. What happens, and why? Put it back afterwards.

📄 View solution
Exercise 3

Write a .gitignore for this project, and explain why each entry is there. Then modify script.ts so that running it twice doesn't fail.

📄 View solution

Chapter 2 Quick Reference

  • Node 20.19+; "type": "module" in package.json; TypeScript run with tsx
  • Pin Prisma 7: prisma@7, @prisma/client@7, and the adapter @7 — plain prisma installs a Prisma 8 release candidate
  • npx prisma init --datasource-provider sqlite --output ../generated/prisma
  • Generator prisma-client with a required output; the datasource has only the provider
  • prisma7.config.ts (prisma.config.ts before 7.10) holds the schema path, migrations path and database URL; it must import "dotenv/config"
  • npx prisma migrate dev --name init, then npx prisma generate after every schema change
  • Create one client in lib/prisma.ts with a driver adapter; import it from generated/prisma/client