Skip to main content

How to Set a Maximum String Length in EF Core (varchar Instead of longtext in MySQL)

· 7 min read
Jagdish Kumawat
Founder @ Dewiride

A C# string has no length limit, so without being told otherwise, EF Core's MySQL provider gives each one the biggest text type MySQL has: longtext, up to 4 GB. That's wasteful for a SKU, and it gets in the way of indexes. This guide sets real maximum lengths so columns become varchar(n), applies the change to a table that already has data, and shows what happens when you index a string without a length.

What a Maximum Length Does​

EF Core's entity properties page explains: "Configuring a maximum length provides a hint to the database provider about the appropriate column data type to choose for a given property." The provider turns it into the database's type: here, varchar(n). And EF Core doesn't enforce it itself: "Entity Framework does not do any validation of maximum length before passing data to the provider."

Prerequisites​

Step 1: See the Default​

A product has a SKU, a name and a description, all strings:

src/Dewiride.Inventory.Data/Entities/Product.cs (excerpt)
public required string Sku { get; set; }

public required string Name { get; set; }

public string? Description { get; set; }

The first migration, with no configuration, made all three longtext:

Migrations/…_CreateCatalogTables.cs (excerpt)
Sku = table.Column<string>(type: "longtext", nullable: false),
Name = table.Column<string>(type: "longtext", nullable: false),
Description = table.Column<string>(type: "longtext", nullable: true),

Step 2: Set the Lengths​

Choose a length for each string from what it really holds: SKUs are short codes, names fit in a line, and a description can stay long. In the configuration:

src/Dewiride.Inventory.Data/Configurations/ProductConfiguration.cs (excerpt)
builder.Property(p => p.Sku)
.HasMaxLength(32);

builder.Property(p => p.Name)
.HasMaxLength(200);

// Description has no maximum length on purpose: MySQL stores it as longtext.
src/Dewiride.Inventory.Data/Configurations/CategoryConfiguration.cs (excerpt)
builder.Property(c => c.Name)
.HasMaxLength(100);

The same can be written as an attribute on the property, [MaxLength(32)]. For a default length for every string in the model, ConfigureConventions has configurationBuilder.Properties<string>().HaveMaxLength(…); per-property lengths override it.

Step 3: Read the Migration​

Terminal
dotnet ef migrations add SetMaxLengths --project src/Dewiride.Inventory.Data --startup-project src/Dewiride.Inventory.Api
Output
Build started...
Build succeeded.
An operation was scaffolded that may result in the loss of data. Please review the migration for accuracy.
Done. To undo this action, use 'ef migrations remove'
Its SQL (dotnet ef migrations script LowercaseTableNames SetMaxLengths)
START TRANSACTION;
ALTER TABLE `products` MODIFY `Sku` varchar(32) NOT NULL;

ALTER TABLE `products` MODIFY `Name` varchar(200) NOT NULL;

ALTER TABLE `categories` MODIFY `Name` varchar(100) NOT NULL;

INSERT INTO `__EFMigrationsHistory` (`MigrationId`, `ProductVersion`)
VALUES ('20261103043648_SetMaxLengths', '10.0.14');

COMMIT;

A terminal where dotnet ef migrations add SetMaxLengths warns about possible data loss, and the generated SQL modifies Sku to varchar(32), Name to varchar(200) and the category Name to varchar(100).

The warning is real: a shorter column can't hold longer values. EF Core doesn't look at your data, so check it yourself.

Step 4: Check the Data, Then Apply​

Look for values longer than the new limits before applying. CHAR_LENGTH counts characters, which is what varchar(n) limits:

mysql>
SELECT Id, Sku, CHAR_LENGTH(Name) AS NameLength FROM products WHERE CHAR_LENGTH(Name) > 200;
Output
+----+-------------+------------+
| Id | Sku | NameLength |
+----+-------------+------------+
| 4 | ADP-HDMI-02 | 246 |
+----+-------------+------------+
1 row in set (0.000 sec)

One product had a 246-character name. Applied with that row in place, the migration failed with Data too long for column 'Name' at row 2, after it had already changed the Sku column, because MySQL can't roll back schema changes. That error has its own post. After shortening the name, the migration applied:

Output (dotnet ef database update, the lines that matter)
Applying migration '20261103043648_SetMaxLengths'.
ALTER TABLE `products` MODIFY `Sku` varchar(32) NOT NULL;
ALTER TABLE `products` MODIFY `Name` varchar(200) NOT NULL;
ALTER TABLE `categories` MODIFY `Name` varchar(100) NOT NULL;
INSERT INTO `__EFMigrationsHistory` (`MigrationId`, `ProductVersion`)
VALUES ('20261103043648_SetMaxLengths', '10.0.14');
Done.
mysql>
DESCRIBE products;
Output (the string columns, in the finished table; the UNI on Sku comes from a unique index added later)
| Sku | varchar(32) | NO | UNI | NULL | |
| Name | varchar(200) | NO | | NULL | |
| Description | longtext | YES | | NULL | |

Why Indexed Strings Need a Length​

MySQL can't index a whole longtext column. When I added a unique index to a string that still had no maximum length, Oracle's provider didn't fail; it changed the column on its own:

The migration for HasIndex(c => c.Name).IsUnique(), with no maximum length set
migrationBuilder.AlterColumn<string>(
name: "Name",
table: "categories",
type: "varchar(255)",
nullable: false,
oldClrType: typeof(string),
oldType: "longtext");

migrationBuilder.CreateIndex(
name: "IX_categories_Name",
table: "categories",
column: "Name",
unique: true);

varchar(255), a length nobody chose. Set the length yourself before indexing a string, as in Step 2, and the index uses the column you designed.

Common Mistakes​

MistakeWhat happensDo this instead
No maximum length on short stringslongtext columns that can't be fully indexedHasMaxLength for every string with a natural limit
Shrinking a column without checking dataThe migration fails halfwaySELECT … WHERE CHAR_LENGTH(col) > n first
Choosing lengths in bytesvarchar(n) counts charactersThink in characters
Relying on the database to reject long inputUsers get a database errorValidate lengths in the API too

Troubleshooting​

SymptomLikely causeFix
Data too long for column '…' when savingA value is longer than the columnValidate input, or raise the length
Data too long while applying a migrationExisting rows are longer than the new limitFix the rows, then apply again
A string column became varchar(255)An index on a string without a lengthSet HasMaxLength explicitly

FAQ​

Is longtext ever right?​

Yes, for text with no natural limit and no index, such as a product description or notes. The description here stays longtext on purpose.

Does a bigger varchar cost more storage?​

MySQL stores a varchar value as its actual characters plus a small length prefix, so varchar(200) holding 20 characters stores about 20. Choose lengths for meaning, not to save space.

Conclusion​

EF Core's MySQL provider maps a string without a maximum length to longtext. Set real limits with HasMaxLength(n) or [MaxLength(n)] so columns become varchar(n), check existing data with CHAR_LENGTH before a migration shrinks a column, and always give a string a length before indexing it, or the provider will pick varchar(255) for you.

Additional Resources​

Stay Updated

Subscribe to our newsletter for the latest tutorials, tech insights, and developer news.

By subscribing, you agree to our privacy policy. Unsubscribe at any time.