---
id: schema-basic-objects
title: Basic Object Schemas
category: objects
skillLevel: beginner
tags:
  - schema
  - object
  - struct
  - basics
lessonOrder: 9
rule:
  description: >-
    Basic Object Schemas.
summary: >-
  Most real data is objects with named fields. You need to define the expected shape, validate each field has the right type, and get a typed result. Without schema validation, you access properties...
---

# Problem

Most real data is objects with named fields. You need to define the expected shape, validate each field has the right type, and get a typed result. Without schema validation, you access properties that might not exist or have the wrong type.

# Solution

```typescript
import { Schema } from "effect"

// ============================================
// BASIC STRUCT DEFINITION
// ============================================

const User = Schema.Struct({
  id: Schema.String,
  name: Schema.String,
  age: Schema.Number,
  isActive: Schema.Boolean,
})

// Extract TypeScript type
type User = typeof User.Type

// Decode unknown data
const decode = Schema.decodeUnknownSync(User)

const user = decode({
  id: "user_123",
  name: "Alice",
  age: 30,
  isActive: true,
})

console.log(`✅ ${user.name}, age ${user.age}`)

// ============================================
// MULTIPLE STRUCTS
// ============================================

const Address = Schema.Struct({
  street: Schema.String,
  city: Schema.String,
  zipCode: Schema.String,
  country: Schema.String,
})

const Product = Schema.Struct({
  sku: Schema.String,
  name: Schema.String,
  price: Schema.Number,
  inStock: Schema.Boolean,
})

const Order = Schema.Struct({
  orderId: Schema.String,
  total: Schema.Number,
  itemCount: Schema.Number,
})

type Address = typeof Address.Type
type Product = typeof Product.Type
type Order = typeof Order.Type

// ============================================
// VALIDATION IN ACTION
// ============================================

const decodeAddress = Schema.decodeUnknownSync(Address)
const decodeProduct = Schema.decodeUnknownSync(Product)

// Valid address
const address = decodeAddress({
  street: "123 Main St",
  city: "Springfield",
  zipCode: "12345",
  country: "USA",
})
console.log(`✅ ${address.city}, ${address.country}`)

// Valid product
const product = decodeProduct({
  sku: "WIDGET-001",
  name: "Super Widget",
  price: 29.99,
  inStock: true,
})
console.log(`✅ ${product.name}: $${product.price}`)

// Invalid - missing field
try {
  decodeAddress({
    street: "123 Main St",
    city: "Springfield",
    // Missing zipCode and country!
  })
} catch {
  console.log("❌ Missing required fields")
}

// Invalid - wrong type
try {
  decodeProduct({
    sku: "WIDGET-001",
    name: "Super Widget",
    price: "twenty-nine",  // Should be number!
    inStock: true,
  })
} catch {
  console.log("❌ Price must be a number")
}
```

# Why This Works

| Concept | Explanation |
|---------|-------------|
| **Schema.Struct** | Define object shape with named fields |
| **Field schemas** | Each field validated independently |
| **Type inference** | TypeScript type extracted automatically |
| **All fields required** | Missing fields cause ParseError |
| **Type checking** | Wrong types cause ParseError |

# When to Use

- API request/response bodies
- Form data validation
- Config file parsing
- Database record validation
- Any structured object data

# Related Patterns

- [Optional Fields](./optional-fields.md)
- [Nested Objects](./nested-objects.md)
- [Default Values](./default-values.md)

