ERROR: relation "customers" already exists — a CREATE statement
named a table that is already in the schema. In a script you run more than once, write
CREATE TABLE IF NOT EXISTS. Under EF Core, the table exists but
__EFMigrationsHistory does not list the migration that created it, so make the
history table tell the truth.
dotnet ef migrations list shows the problem at a glance: a migration marked
(Pending) whose tables are already there. Record it as applied with one
INSERT into the history table, but only after checking that the schema really
matches that migration.
The error
CREATE TABLE customers (id int PRIMARY KEY, name text NOT NULL, email text UNIQUE);
ERROR: relation "customers" already exists
The EF Core version, from dotnet ef database update:
Applying migration '20261030025248_InitialCreate'.
Failed executing DbCommand (3ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
CREATE TABLE "Customers" (
"Id" integer GENERATED BY DEFAULT AS IDENTITY,
"Name" text NOT NULL,
"Email" text,
CONSTRAINT "PK_Customers" PRIMARY KEY ("Id")
);
Npgsql.PostgresException (0x80004005): 42P07: relation "Customers" already exists
Why it happens
"Relation" is PostgreSQL's catalog word for tables, indexes, views and sequences, which is why
a repeated CREATE INDEX names a relation too. A plain CREATE never
replaces anything, so running the same script twice fails at the first object it creates.
EF Core decides what to run by reading __EFMigrationsHistory, not by looking at
the tables. If a migration's row is missing, EF Core treats it as pending and runs its
CREATE TABLE again. The test broke the history two ways and got the same error
from both: by deleting the row, and by copying the database with
pg_dump --schema-only, which created an empty history table in the copy (zero
rows) next to a complete Customers table.
The fix
CREATE TABLE IF NOT EXISTS customers (id int PRIMARY KEY, name text NOT NULL, email text UNIQUE);
NOTICE: relation "customers" already exists, skipping
CREATE TABLE
IF NOT EXISTS checks only the name: it does not compare columns, so a table with
an older shape stays as it is. For EF Core, record the migration that the schema already
contains, then update:
INSERT INTO "__EFMigrationsHistory" ("MigrationId", "ProductVersion")
VALUES ('20261030025248_InitialCreate', '10.0.12');
INSERT 0 1
PS> dotnet ef database update
Build started...
Build succeeded.
The Entity Framework tools version '10.0.0' is older than that of the runtime '10.0.12'. Update the tools for the latest features and bug fixes. See https://aka.ms/AAc1fbw for more information.
Acquiring an exclusive lock for migration application. See https://aka.ms/efcore-docs-migrations-lock for more information if this takes too long.
No migrations were applied. The database is already up to date.
Done.
The migration id is the file name in your Migrations folder without
.cs, and the second value is your EF Core version. Insert rows only for
migrations the database really has; a row for one whose changes are missing hides them, and
EF Core will not apply them. For the schema-only copy, bring the history rows along instead
of typing them:
pg_dump -U postgres --data-only --table='"__EFMigrationsHistory"' shopef | psql -U postgres -d shopef2 -q
After that, dotnet ef database update --connection against the copy also
answered No migrations were applied.
How it was reproduced
A postgres:18 container (PostgreSQL 18.4) on Docker 29.9.2 under Windows 11, psql
18.4 inside it, and a .NET 10 console app (SDK 10.0.403) with
Npgsql.EntityFrameworkCore.PostgreSQL 10.0.3, Microsoft.EntityFrameworkCore.Design 10.0.12 and
the dotnet-ef 10.0.0 tool, whose warning about being older than the 10.0.12 runtime is
harmless here. One Customer entity and one
migration, InitialCreate, applied and then broken. The names fix7-pg, shop,
shopef and shopef2 are this test's own, and the container was removed afterwards.
Frequently asked
- How do I fix relation already exists in PostgreSQL?
- In a script that may run twice, use CREATE TABLE IF NOT EXISTS or CREATE INDEX IF NOT EXISTS; PostgreSQL prints a NOTICE and skips the object. If the error comes from EF Core migrations, the table is there but the migration is not recorded in __EFMigrationsHistory; record it once you have checked the schema matches.
- Why does dotnet ef database update try to create a table that already exists?
- EF Core runs every migration that has no row in __EFMigrationsHistory. If the row was deleted, or the database was copied with pg_dump --schema-only, which copies the history table without its rows, the first migration looks pending and its CREATE TABLE runs again. dotnet ef migrations list marks it (Pending).
- Does CREATE TABLE IF NOT EXISTS update an existing table's columns?
- No. It only checks whether a relation with that name exists and skips the statement if it does, whatever columns the existing table has. Use ALTER TABLE to change an existing table.
More decoded errors in the Fixes category. The SQL Server version of the same EF Core situation is There is already an object named in the database (2714).