1048 words
5 minutes
[Astro] Distinguishing Between params and props

The Difference Between params and props in Astro and How to Use Them#

Astro Data Coordination

When developing websites with Astro, I wondered about data passing methods. I became confused about what the two concepts of params and props really are. This article summarizes what I researched about the differences between params and props and how to use them.

Problem: The Data Passing Puzzle in Astro#

When developing with a new Astro project, don’t you encounter questions like these?

  • “When passing data to page components, should I use params or props?”
  • “Why can’t I access Astro.params in interactive components?”
  • “What’s the optimal way to pass data to components in dynamic routes?”

To answer these questions, let’s first organize the basic differences.

Basic Differences Between params and props#

Aspectparamsprops
SourceDynamic segments from routing (e.g., /blog/[slug].astro)Explicitly passed by parent component
Access MethodRetrieved via Astro.paramsRetrieved via Astro.props (received as function arguments)
Access ScopePage / Layout files only (not available in client components)All components (page, layout, client components)
Main UsageData fetching and page generation dependent on URLPassing values to highly reusable UI components
TypingOften manually typed due to dependency on route definitionEasy to define type-safely with interface Props { ... }
Build vs RuntimeAstro automatically injects by parsing URLParent bundles values and injects during rendering
Pitfalls- Empty without dynamic routes
- Not accessible in client components
- Forgetting to pass / type mismatch
- Bloat when passing too much
Representative Patterns- Article pages
- Multi-language ([lang]/[...page].astro)
- Generic cards / buttons
- Layout setting values

Solution: How to Distinguish Usage#

Use the following criteria to distinguish usage:

1. URL Dependency-Based Selection#

Use params when URL structure is the primary source of data:

// src/pages/articles/[category]/[id].astro
---
const { category, id } = Astro.params;
// Use values obtained directly from URL for data fetching
const article = await fetchArticle(category, id);
---

Key Point: Effective when URLs represent user state or navigation history.

2. Maximizing Component Reusability#

Always use props for reusable components:

---
// src/components/Alert.astro
interface Props {
  type: 'info' | 'warning' | 'error';
  message: string;
  dismissable?: boolean;
}

const { type, message, dismissable = true } = Astro.props;
---

<div class={`alert alert-${type}`} data-dismissable={dismissable}>
  <p>{message}</p>
  {dismissable && <button class="close">×</button>}
</div>

Practical Examples:

<Alert type="warning" message="You have unsaved changes" />
<Alert type="error" message="Connection failed" dismissable={false} />

3. Data Fetching and 404 Handling#

Consider handling cases where params values are invalid:

---
// src/pages/products/[id].astro
const { id } = Astro.params;
const product = await getProduct(id);

// Redirect to 404 page if product doesn't exist
if (!product) {
  return Astro.redirect('/404');
}

// Or change only the Status Code
if (!product) {
  Astro.response.status = 404;
}
---

{product ? (
  <ProductDetail item={product} />
) : (
  <ProductNotFound id={id} />
)}

4. Maximizing TypeScript Compatibility#

Use type definitions for type-safe codebases:

// Type definition for params
export interface ProductParams {
  id: string;
  category?: string;
}

// Common type definition for props (reusable)
export interface CardProps {
  title: string;
  description: string;
  imageUrl?: string;
  isPromoted?: boolean;
}

Implementation Example: Practical Code#

Dynamic Blog Article Page Example#

---
// src/pages/blog/[slug].astro
import { getCollection } from 'astro:content';
import BlogLayout from '../../layouts/BlogLayout.astro';
import RelatedPosts from '../../components/RelatedPosts.astro';
import ShareButtons from '../../components/ShareButtons.astro';

// 1. Get slug from params
const { slug } = Astro.params;

// 2. Get content
const posts = await getCollection('blog');
const post = posts.find(post => post.slug === slug);

// 3. 404 if article doesn't exist
if (!post) {
  return Astro.redirect('/404');
}

// 4. Get related posts (articles with same tags)
const relatedPosts = posts
  .filter(p => p.slug !== slug && p.data.tags.some(tag => post.data.tags.includes(tag)))
  .slice(0, 3);

// 5. Prepare to render article content
const { Content } = await post.render();
---

<BlogLayout title={post.data.title} description={post.data.description}>
  <article class="prose lg:prose-xl mx-auto">
    <h1>{post.data.title}</h1>
    
    <div class="metadata">
      <time datetime={post.data.date.toISOString()}>
        {post.data.date.toLocaleDateString('en-US')}
      </time>
      <div class="tags">
        {post.data.tags.map(tag => (
          <a href={`/tags/${tag}`} class="tag">#{tag}</a>
        ))}
      </div>
    </div>
    
    <Content />
    
    <!-- Pass necessary data to components via props -->
    <ShareButtons 
      title={post.data.title} 
      url={`https://myblog.com/blog/${slug}`} 
    />
    
    <RelatedPosts posts={relatedPosts} />
  </article>
</BlogLayout>

Reusable UI Component Example#

---
// src/components/PostCard.astro
interface Props {
  title: string;
  date: Date;
  excerpt: string;
  slug: string;
  featured?: boolean;
}

const { title, date, excerpt, slug, featured = false } = Astro.props;
const formattedDate = date.toLocaleDateString('en-US');
---

<article class={`card ${featured ? 'card-featured' : ''}`}>
  <a href={`/blog/${slug}`}>
    <h2>{title}</h2>
    <p class="excerpt">{excerpt}</p>
    <time datetime={date.toISOString()}>{formattedDate}</time>
  </a>
</article>

<style>
  .card {
    border: 1px solid #eee;
    padding: 1.5rem;
    border-radius: 8px;
    transition: transform 0.2s, box-shadow 0.2s;
  }
  
  .card:hover {
    transform: translateY(-3px);
    box-shadow: 0 10px 20px rgba(0,0,0,0.1);
  }
  
  .card-featured {
    border-left: 4px solid #7c3aed;
    background-color: #f5f3ff;
  }
</style>

Common Mistakes and Solutions#

Mistake 1: Trying to access params from client components#

---
// ❌ This doesn't work
---
<script>
  // Astro.params is not available on the client side
  console.log(Astro.params.slug);  // Error!
</script>

Solution: Pass necessary values through data attributes

---
const { slug } = Astro.params;
---
<div data-article-id={slug}>
  <script>
    // Access via data attributes
    const container = document.querySelector('[data-article-id]');
    const slug = container.dataset.articleId;
    console.log('Article slug:', slug);
  </script>
</div>

Mistake 2: Omitting props typing#

---
// ❌ No types, can't prevent incorrect usage
const { titl } = Astro.props; // Typos won't be warned about
---

Solution: Always define Props interface

---
// ✅ Type-safe props handling
interface Props {
  title: string;
  description?: string;
}

const { title, description = '' } = Astro.props;
---

Summary: Points to Keep in Mind!#

Points for efficient Astro project development!!:

  1. Think of params as “input from URL”

    • Important information related to user navigation
    • Use for URL structures that are meaningful for SEO
  2. Design props as “component API”

    • Have explicit interfaces
    • Ensure robustness with default values and types
  3. Always be conscious of data flow

    • The basic flow is params → data fetching → props
    • From URL through database or API to UI components
  4. Proper error handling

    • Don’t forget to validate params input values
    • Handle 404 and other error states appropriately

Following these principles should make your Astro projects surprisingly manageable! 🚀 Even for large sites or projects requiring long-term operation, incorporating these patterns from the beginning should greatly reduce occasions for sighing “This will be hard to fix later…” ✨

Finally: Checklist for Data Management in Astro#

I’ve compiled a checklist useful when starting new Astro projects or improving existing ones:

  1. Diagram data flow

    • Clarify data flow from URL to components
    • Map which values are needed by which components
  2. Create type definitions first

    • Create type definitions for params and props upfront
    • Decide interface design in advance
  3. Clarify component responsibilities

    • Page components: Data fetching and overall structure
    • UI components: Focus only on display
  4. Be performance-conscious

    • Pass only the minimum necessary properties
    • Appropriately divide large data
  5. Write debuggable code

    • Separate complex data transformations into independent functions
    • Make error location identification easy

Astro is a framework with a unique mental model, but once you understand the concepts of params and props, development troubles should decrease!! Probably!

Reference Resources#

[Astro] Distinguishing Between params and props
https://naonao-na.com/en/posts/astro-params-vs-props/
Author
[object Object]
Published at
2025-05-13