TL;DR:
constis a compile-time constant that gets inlined at every use site, no memory address, no runtime existence.staticis a value with a single fixed memory address that lives for the entire program. Useconstfor values used in computation (array sizes, numeric constants). Usestaticwhen you need a single shared instance, a global config, aMutex, or aOnceCell. Preferconstby default.
What Is const?
const declares a compile-time constant, a value evaluated at compile time and substituted inline wherever it's used. It has no memory address and never appears at runtime.
const MAX_CONNECTIONS: usize = 100;
const PI: f64 = 3.14159265358979;
const GREETING: &str = "Hello, world!";
fn main() {
let arr = [0u8; MAX_CONNECTIONS]; // const used as array size
println!("{}", PI * 2.0);
// Every use of MAX_CONNECTIONS is replaced with 100 at compile time
// There is no "MAX_CONNECTIONS variable" in the binary
}const must have an explicit type and its value must be evaluable at compile time (no heap allocation, no runtime I/O).
What Is static?
static declares a value with a 'static lifetime, it lives for the entire duration of the program and has a single fixed memory address.
static HELLO: &str = "Hello";
static MAX: usize = 1000;
// Often used for global state that needs a stable address
use std::sync::OnceLock;
static CONFIG: OnceLock<AppConfig> = OnceLock::new();
fn get_config() -> &'static AppConfig {
CONFIG.get_or_init(|| AppConfig::load())
}static values are stored in the binary's data segment. Their address is the same everywhere the static is used, unlike const, which may be inlined at multiple locations.
What Is the Difference Between const and static?
const is inlined; static has a stable address. Use const for numbers and simple values. Use static when you need a single shared instance.
const | static | |
|---|---|---|
| Memory address | None (inlined) | Stable address in binary |
| Lifetime | N/A (no runtime) | 'static (entire program) |
| Mutability | Immutable | Immutable (or unsafe static mut) |
| Type restrictions | Must be Copy for most uses | Any type |
| Common use | Sizes, numbers, string literals | Global state, singletons |
// const; inlined, multiple copies may exist in binary
const BUFFER_SIZE: usize = 4096;
let buf = [0u8; BUFFER_SIZE]; // BUFFER_SIZE replaced with 4096
// static; single memory location
static INSTANCE_COUNT: std::sync::atomic::AtomicUsize =
std::sync::atomic::AtomicUsize::new(0);How Do You Use static for Global State?
Use static with OnceLock, Mutex, or AtomicXxx for thread-safe global state. Avoid static mut, it requires unsafe and is easy to misuse.
use std::sync::{Mutex, OnceLock};
use std::collections::HashMap;
// Lazy-initialized global state
static CACHE: OnceLock<Mutex<HashMap<String, String>>> = OnceLock::new();
fn cache() -> &'static Mutex<HashMap<String, String>> {
CACHE.get_or_init(|| Mutex::new(HashMap::new()))
}
fn main() {
cache().lock().unwrap().insert("key".into(), "value".into());
println!("{:?}", cache().lock().unwrap().get("key"));
}For atomic counters and flags, use AtomicUsize, AtomicBool etc., they're Sync and don't need Mutex.
What Is const fn?
const fn marks a function as callable at compile time, it can be used to compute const values, array sizes, and other compile-time expressions.
const fn square(x: u32) -> u32 {
x * x
}
const SIDE: u32 = 4;
const AREA: u32 = square(SIDE); // evaluated at compile time: 16
fn main() {
println!("area = {AREA}"); // 16; computed before the program ran
}const fn restrictions have loosened over time, loops, conditionals, and many std functions are now const-compatible.
Frequently Asked Questions
No, const values must be fully computable at compile time with no heap allocation. Use const for &str, numbers, arrays with known size, and simple structs of those. For heap-allocated globals, use static with OnceLock.
static mut declares a mutable global variable. Accessing it requires unsafe because multiple threads could read/write it simultaneously, a data race. Use AtomicXxx, Mutex, or RwLock instead.
'static means "lives for the entire program." static variables have 'static lifetime by definition. String literals like "hello" are also 'static. A function returning &'static str is returning a reference that will never be invalidated.
Before std::sync::OnceLock was stabilized (Rust 1.70), lazy_static and once_cell were the standard way to initialize complex global statics lazily. Today, OnceLock (for single values) and LazyLock (for lazy init) cover most cases without extra dependencies.
Sources
Related Glossary Terms
- Ownership:
staticvalues have'staticlifetime, they're never dropped - Lifetime:
'staticis the longest possible lifetime in Rust - Mutex:
static Mutex<T>is the standard global mutable state pattern - Unsafe:
static mutrequiresunsafe, prefer atomic types orMutexinstead - once-cell:
OnceLockand once_cell are the ergonomic runtime-initialized alternative to many statics
Keep Reading
- Rust Ownership and Borrowing Explained: const and static sidestep ownership; understanding why requires knowing the rules
- Rust Memory Safety: NSA and CISA: compile-time constants are a key safety primitive

