Question

C# const vs static readonly: When to Use Each

csharpconstants

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 readonly for values that are public
  • use const only for internal, protected, or private values

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, or null

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.

static readonly

A static readonly field is a runtime-initialized value that can only be assigned once.

That means:

  • it belongs to the type, not an instance
  • it can be assigned when declared or inside a static constructor
  • its value is evaluated at runtime
  • consumers read the field from the assembly at runtime, so changes are picked up without recompiling dependent code

Example:

public static readonly DateTime LaunchDate = DateTime.UtcNow;

This cannot be const because DateTime.UtcNow is not known at compile time.

Why this matters

The biggest practical difference is versioning and deployment safety.

  • const is great for values that are truly universal and never expected to change
  • static readonly is safer for publicly exposed values, especially across assemblies

That is why many developers avoid public const unless the value is a true mathematical or protocol constant.

Should public values always be static readonly?

Not always, but often that is the safer default.

A good rule of thumb:

  • use const for values that are truly permanent and compile-time constant
  • prefer public static readonly for public values that might ever change
  • use a property when you need logic, lazy computation, validation, or API flexibility

Should you use properties instead?

Sometimes, yes.

A property is useful when:

  • you may want to change implementation later
  • the value is computed
  • the value comes from configuration or environment
  • you want to preserve encapsulation

Example:

public static string AppName { get; } = "Inventory Service";

This behaves similarly to a read-only exposed value, but gives you more flexibility than a field in public APIs.

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.

Take Quiz

Syntax and Examples

Core syntax

const

private const int DefaultTimeoutSeconds = 30;
public const string CompanyName = "Acme";

Notes:

  • const is automatically static
  • you cannot write static const in 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

public class AppSettings
{
    public const string FileExtension = ".json";
    public static readonly string StartupFolder = Environment.CurrentDirectory;
}

Why these choices?

  • FileExtension is a true compile-time literal, so const is reasonable
  • StartupFolder depends on the environment at runtime, so it must be static readonly

Example with a property

public class AppInfo
{
    public static string Name { get; } = "Order Processor";
}

This is useful when you want a public read-only value but may want implementation flexibility later.

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:

Console.WriteLine(3);

2. The compiler sees static readonly

public static readonly int DefaultDelayMs = 500;

This field belongs to the class and is initialized when the type is loaded.

The compiled program keeps it as a field lookup, not as a copied literal.

3. Main runs

When Main starts:

  • Limits.MaxRetries is already effectively known as 3
  • Limits.DefaultDelayMs is read from the Limits type at runtime

4. Output

3
500

Why this matters in shared libraries

Suppose library version 1 has:

public const int Timeout = 30;

Another app compiles against it. Later the library changes to:

public const int Timeout = 60;

If the app is not recompiled, it may still use 30 because that value was copied into its compiled code.

If the field had been:

public static readonly int Timeout = 30;

then changing it to 60 in the library would be picked up at runtime when the app loads the updated assembly.

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;

When a property is better

Use a property when the value is part of your public API and you want room to change the implementation later.

Examples:

  • application name from config
  • feature flags
  • values computed once and cached
  • values that may later require validation or transformation
public static string ApiVersion { get; } = "v1";
Take Quiz

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 { get; } = 50;

This lets you later change the implementation without forcing callers to change syntax.

4. Validation and configuration: property or method

If the value may come from config or require checks, a property is clearer than a field.

public static string ConnectionName => AppConfig.Current.ConnectionName;

5. Expensive reusable objects: static readonly

Developers often use static readonly for shared objects that should only be created once.

private static readonly HttpClient Client = new HttpClient();

This is not a constant value, but it is a common real-world use of static readonly.

Practical recommendation

  • private const for true literals used internally
  • public static readonly for exposed fixed values that might change later
  • public read-only property when API flexibility matters more than direct field access

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.UtcNow is 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 int DefaultLimit = 25;

3. Assuming readonly means deeply immutable

This is legal:

public static readonly List<string> Names = new List<string>();

But the list contents can still change:

Names.Add("Alice");

readonly means the field reference cannot be reassigned, not that the object itself is immutable.

Safer alternatives:

  • expose immutable collections
  • return read-only wrappers
  • use properties with controlled access

4. Writing static const

This is invalid in C#:

public static const int Size = 10;

Use:

public const int Size = 10;

const is already static.

5. Using a field when a property would better protect your API

A public field exposes implementation more directly.

Instead of:

public static readonly string Name = "Service A";

consider:

public static string Name { get; } = "Service A";

This gives more flexibility for future changes.

Comparisons

const vs static readonly vs property

Featureconststatic readonly fieldRead-only property
Known at compile timeYesNoUsually no
Implicitly staticYesNoNo
Can use runtime expressionNoYesYes
Value copied into calling assemblyYesNoNo
Safe for public library versioningUsually less safeSaferSafer
Can expose logic laterNoNoYes
Good for private literalsYesSometimesSometimes
Good for public API valuesSometimesYesYes

Quick guidance

SituationRecommended choice
Truly fixed literal, internal useconst
Public value that may change laterstatic readonly
Public API where flexibility mattersRead-only property
Runtime-generated valuestatic readonly or property
Shared object instancestatic readonly

readonly vs const

readonly by itself is for instance fields:

public readonly int Port;

public MyClass()
{
    Port = 8080;
}

That is different from static readonly, which belongs to the type rather than each object instance.

Take Quiz

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 { get; } = "Billing Service";

Rules to remember

  • const is implicitly static
  • const values are inlined into compiled code
  • static readonly is evaluated at runtime
  • readonly protects reassignment, not object mutation
  • avoid public const unless the value is truly permanent

Common edge case

This is read-only, but not immutable:

public static readonly List<int> Numbers = new List<int>();

You cannot reassign Numbers, but you can still change its contents.

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?

No, not in general. Those values are not compile-time constants in the way C# requires for const.

Are string constants safe as public const?

Technically yes, but the same versioning rule still applies. If the string could ever change, public static readonly or a property is safer.

Take Quiz

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 const value for a true compile-time literal.
  • Add one static readonly value that uses a runtime expression.
  • Add one public read-only property for a fixed application value.
  • Write a Main method that prints all three values.
  • Keep the code valid C# and easy to read.
Take Quiz

Keep learning

Related questions

View more