Skip to content
Fe 26.0 is not production-ready. This is an initial release of a new compiler. Learn more

Primitive Types

Fe provides a set of primitive types that form the foundation for all data manipulation. These types are built into the language and are always available without imports.

The bool type represents a logical value that can be either true or false.

let is_active: bool = true
let has_permission: bool = false

Booleans are commonly used in conditional expressions and control flow:

if is_active {
// do something
}
let result = is_active && has_permission

Fe provides both signed and unsigned integers in various sizes. The number in the type name indicates the bit width.

Unsigned integers can only represent non-negative values (zero and positive numbers).

TypeBitsMinimumMaximum
u880255
u1616065,535
u323204,294,967,295
u6464018,446,744,073,709,551,615
u12812802¹²⁸ - 1
u25625602²⁵⁶ - 1
usize*0platform-dependent
let small: u8 = 255
let balance: u256 = 1000000000000000000 // 1 ETH in wei
let count: u32 = 42

Signed integers can represent both negative and positive values, using two’s complement representation.

TypeBitsMinimumMaximum
i88-128127
i1616-32,76832,767
i3232-2,147,483,6482,147,483,647
i6464-2⁶³2⁶³ - 1
i128128-2¹²⁷2¹²⁷ - 1
i256256-2²⁵⁵2²⁵⁵ - 1
isize*platform-dependentplatform-dependent
let temperature: i32 = -10
let offset: i256 = -500

The Ethereum Virtual Machine (EVM) natively operates on 256-bit words. This means:

  • u256 and i256 are the most gas-efficient types for most operations, as they match the EVM’s native word size
  • Smaller types like u8 or u32 may require additional masking operations, potentially using more gas
  • Use smaller types when storage packing is important or when interfacing with external systems that expect specific sizes

For most smart contract development, prefer u256 for unsigned values and i256 for signed values unless you have a specific reason to use smaller types.

// Recommended for most EVM operations
let amount: u256 = 1000
let price: u256 = 500
// Use smaller types when needed for storage packing or external interfaces
let percentage: u8 = 100

Fe supports several formats for writing numeric literals:

Standard base-10 numbers:

let x: u256 = 42
let large: u256 = 1000000

Use underscores to make large numbers more readable. Underscores are ignored by the compiler:

let wei_per_eth: u256 = 1_000_000_000_000_000_000
let million: u256 = 1_000_000

Prefix with 0x or 0X for base-16 numbers. Useful for addresses, hashes, and bit patterns:

let color: u256 = 0xff5733
let mask: u256 = 0xFFFFFFFF
let address_value: u256 = 0x742d35Cc6634C0532925a3b844Bc9e7595f5e123

Prefix with 0b or 0B for base-2 numbers. Useful for bit flags and masks:

let flags: u8 = 0b1010
let permission_mask: u8 = 0b11110000

Prefix with 0o or 0O for base-8 numbers:

let file_mode: u16 = 0o755
let octal_value: u16 = 0o177

The String type represents text data.

let greeting = "Hello, Fe!"
let empty = ""

String literals are enclosed in double quotes. Escape sequences can be used for special characters:

let with_newline = "Line 1\nLine 2"
let with_quote = "She said \"Hello\""

Fe can often infer types from context, so explicit type annotations aren’t always required:

let x: u256 = 42 // type annotation required for integers
let flag = true // inferred as bool
let name = "Alice" // inferred as String<5>

However, explicit type annotations are recommended when the intended type isn’t obvious or when you need a specific integer size:

let amount: u256 = 100 // explicitly u256, not inferred default
let small: u8 = 50 // explicitly u8 for storage efficiency

The Address type represents a 20-byte EVM address. It is a built-in type, always available without imports:

let zero = Address::zero()
let addr = Address { inner: 0x742d35Cc6634C0532925a3b844Bc9e7595f5e123 }

Address is used throughout contract code for account references, access control, and token operations. The Ctx effect provides the caller’s address:

let sender: Address = ctx.caller()