Question
In C#, what is the practical difference between const and static readonly fields, and when should each be used?
I have classes that contain only constant-like values used in different parts of our system. I want to confirm whether this guideline makes sense:
- use
static readonlyfor values that arepublic - use
constonly forinternal,protected, orprivatevalues
Also, what is the recommended approach in general? In some cases, should I use properties instead of static readonly fields?
Short Answer
By the end of this page, you will understand how const and static readonly differ in C#, especially in terms of compile-time behavior, versioning, and runtime initialization. You will also learn when a property is a better choice than either field, and how developers typically expose fixed values safely in real codebases.
Concept
In C#, both const and static readonly are used for values that should not change during normal program execution, but they are not the same thing.
const
A const field is a compile-time constant.
That means:
- its value must be known at compile time
- the compiler replaces uses of the constant with the actual value
- it is implicitly
static - it can only hold certain kinds of values, such as numeric literals,
bool,char,string, ornull
Example:
public const int MaxItems = 100;
Anywhere MaxItems is used, the compiler may substitute 100 directly into the compiled code.
This is important because if a public const value changes in one assembly, other assemblies that already compiled against it may still use the old value until they are recompiled.
Mental Model
Think of const as printing a value directly onto every copy of a document.
If the value is 100, every place that uses it gets 100 written directly into the compiled code. If you later change it to 200, old compiled code still says 100 until it is rebuilt.
Think of static readonly as putting the value in a shared box with a label.
Everyone looks up the value in that box at runtime. If the library is updated, callers read the new value from the box without needing the constant copied into their own code.
Think of a property as a service desk.
Instead of reaching directly into a box, callers ask for the value. Today the desk may just hand back a fixed number. Later it could compute the value, read config, cache data, or log access without changing how callers use it.
Syntax and Examples
Core syntax
const
private const int DefaultTimeoutSeconds = 30;
public const string CompanyName = "Acme";
Notes:
constis automaticallystatic- you cannot write
static constin C# - the value must be known at compile time
static readonly
private static readonly int DefaultPort = 8080;
public static readonly Guid EmptyId = Guid.Empty;
Notes:
- can be assigned at declaration or in a static constructor
- value is fixed after initialization
- can use runtime expressions
Beginner-friendly example
{
FileExtension = ;
StartupFolder = Environment.CurrentDirectory;
}
Step by Step Execution
Consider this example:
public class Limits
{
public const int MaxRetries = 3;
public static readonly int DefaultDelayMs = 500;
}
public class Program
{
public static void Main()
{
Console.WriteLine(Limits.MaxRetries);
Console.WriteLine(Limits.DefaultDelayMs);
}
}
What happens step by step
1. The compiler sees const
public const int MaxRetries = 3;
The compiler knows the value immediately. When Limits.MaxRetries is used, it may replace that usage with 3 directly.
So this line:
Console.WriteLine(Limits.MaxRetries);
can behave like:
Real World Use Cases
When const is commonly used
const is best for values that are genuinely fixed and unlikely to ever change.
Examples:
- numeric conversion factors used internally
- fixed formatting tokens
- private string keys used in one class
- protocol values that are truly defined and stable
private const string JsonContentType = "application/json";
private const int BitsPerByte = 8;
When static readonly is commonly used
static readonly is a good fit for values exposed by libraries or values initialized from runtime APIs.
Examples:
- default timeouts
- shared empty collections
- regex instances
- paths, culture info, or environment-dependent values
- publicly exposed defaults in reusable packages
public static readonly TimeSpan DefaultTimeout = TimeSpan.FromSeconds(30);
public static readonly StringComparer UserNameComparer = StringComparer.OrdinalIgnoreCase;
Real Codebase Usage
In real codebases, developers usually choose between these options based on API stability, versioning, and future flexibility.
Common patterns
1. Private implementation detail: often const
If a value is only used inside one class and is definitely fixed, const is simple and clear.
private const int CacheKeyLength = 16;
2. Public library value: often static readonly
If external code may depend on the value, static readonly avoids the versioning problem of public const.
public static readonly int DefaultPageSize = 50;
3. Exposed API surface: often property
Properties are often preferred for public APIs because they preserve encapsulation.
public static int DefaultPageSize { ; } = ;
Common Mistakes
1. Using const for values that are not compile-time constants
This does not compile:
public const DateTime Start = DateTime.UtcNow;
Why it fails:
DateTime.UtcNowis evaluated at runtime
Use this instead:
public static readonly DateTime Start = DateTime.UtcNow;
2. Exposing public const in shared libraries without thinking about versioning
Broken design example:
public const int DefaultLimit = 25;
If another project compiles against this and you later change it to 50, the other project may still use 25 until rebuilt.
Safer option:
public static readonly DefaultLimit = ;
Comparisons
const vs static readonly vs property
| Feature | const | static readonly field | Read-only property |
|---|---|---|---|
| Known at compile time | Yes | No | Usually no |
| Implicitly static | Yes | No | No |
| Can use runtime expression | No | Yes | Yes |
| Value copied into calling assembly | Yes | No | No |
| Safe for public library versioning | Usually less safe | Safer | Safer |
Cheat Sheet
Quick reference
Use const when
- the value is known at compile time
- the value is truly fixed
- it is often private/internal implementation detail
private const int MaxItems = 100;
public const string Prefix = "INV-";
Use static readonly when
- the value is set at runtime
- the value may change between library versions
- you need a shared object or non-literal value
public static readonly TimeSpan Timeout = TimeSpan.FromSeconds(30);
private static readonly string Root = Environment.CurrentDirectory;
Use a property when
- you want API flexibility
- you may later compute the value
- the value comes from config or logic
public static string Name { ; } = ;
FAQ
Is const faster than static readonly in C#?
Usually the performance difference is not the main concern. The more important issue is semantics: const is compile-time and static readonly is runtime-initialized.
Why do people avoid public const in libraries?
Because constants are inlined into consuming assemblies. If the value changes, dependent projects may still use the old value until they are recompiled.
Can static readonly replace const everywhere?
Often yes, but const is still useful for true compile-time literals and for places where a compile-time constant is required.
Is readonly the same as immutable?
No. readonly only prevents reassigning the field. If the field refers to a mutable object, that object can still change.
Should I use a property instead of a public field?
For public APIs, often yes. A property gives you more flexibility to change implementation later without affecting callers.
Can a const be a DateTime or Guid?
Mini Project
Description
Create a small C# class that exposes application settings using const, static readonly, and properties. This helps you practice choosing the right tool for different kinds of values: compile-time literals, runtime values, and public API-friendly accessors.
Goal
Build a settings class that correctly uses const, static readonly, and a read-only property for different scenarios.
Requirements
- Add one
constvalue for a true compile-time literal. - Add one
static readonlyvalue that uses a runtime expression. - Add one public read-only property for a fixed application value.
- Write a
Mainmethod that prints all three values. - Keep the code valid C# and easy to read.
Keep learning
Related questions
AddTransient vs AddScoped vs AddSingleton in ASP.NET Core Dependency Injection
Learn the differences between AddTransient, AddScoped, and AddSingleton in ASP.NET Core DI with examples and practical usage.
C# Type Checking Explained: typeof vs GetType() vs is
Learn when to use typeof, GetType(), and is in C#. Understand exact type checks, inheritance, and safe type testing clearly.
C# Version Numbers Explained: C# vs .NET Framework and Why “C# 3.5” Is Incorrect
Learn the correct C# version numbers, how they map to .NET releases, and why terms like C# 3.5 are inaccurate and confusing.