JUNE 10, 2025

6 MIN READ

SYLVAIN UTARD

Behind the Stack

Behind the Stack

Our tech stack: Rails for backend velocity, Rust for high-performance ingestion, React and Urql for UIs, Iceberg for data lake, Trino for federated queries.

Listen to this article (Gen-AI)

0:00
3:56
Blog

Why These Choices Matter

At Altertable, we're building an AI-native analytics platform that needs to handle massive data volumes while staying fast and developer-friendly. Our stack isn't just about individual technologies—it's about how they work together to create something greater than the sum of their parts.

Here's the story of our architecture, following the journey from raw data ingestion to beautiful, responsive dashboards.

The Big Picture: How It All Fits Together

Before diving into specifics, here's how our stack works as a unified system:

  1. Data flows in through our Rust-powered ingestion pipeline into Apache Iceberg
  2. Query engines (Trino, DuckDB) provide fast access to lakehouse data
  3. Rails + GraphQL serves as our API layer and business logic hub
  4. React + Urql creates responsive, type-safe user interfaces
  5. AI agents access everything through the same APIs via our internal MCP server
  6. Background jobs (Faktory) orchestrate AI agents and async workflows

Each piece serves a specific purpose, but they're designed to work seamlessly together.

1. Data Ingestion with Rust + Apache Iceberg

Our data journey starts with Rust. We chose Rust for ingestion because when you're processing terabytes of data, performance and memory safety aren't luxuries. They're requirements.

We write directly to Apache Iceberg, giving us:

  • Transactional writes (no more corrupt data from failed jobs)
  • Schema evolution (add columns without breaking existing queries)
  • Time travel (query data as it existed at any point in time)

We use axum for our ingestion APIs, which gives us async performance with minimal overhead. The Rust layer focuses on one thing: getting data into our lakehouse as quickly and reliably as possible.

2. Query Layer - Trino for Federation, DuckDB for Speed

Here's where our query strategy gets interesting. We use different engines for different needs:

Trino for Federated Queries

Trino lets us join our lakehouse data with customer databases in real-time—no ETL required:

-- Join internal events with customer's PostgreSQL users
SELECT
e.user_id,
u.email,
COUNT(*) as event_count
FROM iceberg.events e
JOIN postgres.customer_users u ON e.user_id = u.id
GROUP BY e.user_id, u.email;

We extend Trino with custom Java plugins using its SPI system. While Java might not be trendy in 2025, it's proven itself for data infrastructure. Elasticsearch, Kafka, and Solr all use it, and Trino's plugin architecture makes extending it straightforward.

DuckDB for Interactive Analytics

For real-time dashboards that need sub-second response times, we're integrating DuckDB. Its columnar storage and aggressive optimizations make it perfect for the kind of time-series analytics our users expect.

3. API Layer with Rails + GraphQL

Ruby on Rails serves as our API backbone. After 15+ years with Rails, we know how to move fast without sacrificing quality. RSpec keeps our test coverage high, and Rails' conventions let us focus on business logic instead of boilerplate.

We expose everything through GraphQL, which gives us a clean, consistent API surface:

# app/graphql/types/chart_type.rb
module Types
class ChartType < Types::BaseObject
field :id, ID, null: false
field :title, String, null: false
field :data_points, [Types::DataPointType], null: false
def data_points
# Use DataLoader to prevent N+1 queries
dataloader.with(AssociationLoader, Chart, :data_points).load(object)
end
end
end

GraphQL's type system and introspection capabilities are crucial for the next layer: our frontend.

4. Frontend with React + TypeScript + Urql

Our frontend is React + TypeScript, styled with Tailwind CSS, and powered by Urql for GraphQL.

The key to our frontend architecture is fragment composition. Each component defines exactly what data it needs:

// components/ChartWidget.tsx
import { DataPoint } from './DataPoint';
export const ChartWidget = ({ chart }: Props) => {
return (
<div className="p-4 border rounded-lg bg-white">
<h3 className="text-lg font-semibold">{chart.title}</h3>
<div className="mt-4">
{chart.data_points.map(point => (
<DataPoint key={point.id} point={point} />
))}
</div>
</div>
);
};
ChartWidget.fragments = {
chart: gql`
fragment ChartWidget_chart on Chart {
id
title
data_points {
...DataPoint_point
}
}
${DataPoint.fragments.point}
`,
};

Parent components compose these fragments into complete queries. GraphQL Codegen ensures end-to-end type safety. If the backend schema changes, TypeScript catches the mismatch at compile time.

This approach keeps our frontend modular and ensures we only fetch the data we actually render.

5. AI-Native Architecture with MCP

Here's what makes Altertable truly AI-native: our internal MCP server mirrors our GraphQL API, giving AI agents the same access to data and actions that our frontend has.

No special endpoints. No duplicate logic. Agents can explore data, propose insights, and trigger actions through the same authenticated, structured interface that powers our web app.

This shared contract means humans and agents collaborate through identical interfaces. It's a foundational pattern for AI-native platforms.

Building with AI at this level fundamentally changes how we approach software development. Read about how AI-first development transforms the craft.

6. Background Orchestration with Faktory

Faktory serves as our async job orchestration system, handling everything from AI agent workflows to background analytics tasks. We chose Faktory because it's language-agnostic. We can have Ruby workers handling business logic and Rust workers running AI agents, all in the same queue.

# Ruby worker for orchestrating AI workflows
class AgentWorkflowWorker
include Faktory::Job
def perform(workflow_id, context)
workflow = AgentWorkflow.find(workflow_id)
workflow.execute_with_context(context)
end
end

This separation keeps our real-time APIs responsive while AI agents and heavy background processing happen asynchronously. It's the glue that lets our AI-native features work seamlessly without blocking user interactions.

Why This Stack Works

Our technology choices aren't arbitrary: they're the result of careful consideration of what it takes to build a truly AI-native analytics platform:

  • Speed of iteration: Rails lets us ship features fast
  • Performance at scale: Rust handles our heaviest compute workloads
  • Query flexibility: Trino federates across data sources, DuckDB delivers interactive speed
  • Developer experience: TypeScript + GraphQL Codegen catches errors at compile time
  • AI-first design: Shared APIs mean agents and humans use the same interfaces
  • Reliability: Each layer has a focused responsibility with clear boundaries

The magic happens in how these layers work together, from ingestion to insight, with AI as a first-class citizen throughout.

If building the future of AI-native analytics sounds like your kind of challenge, we're hiring.

Share

Sylvain Utard, Co-Founder & CEO at Altertable

Sylvain Utard

Co-Founder & CEO

Seasoned leader in B2B SaaS and B2C. Scaled 100+ teams at Algolia (1st hire) & Sorare. Passionate about data, performance and productivity.

Stay Updated

Get the latest insights on data, AI, and modern infrastructure delivered to your inbox

Related Articles

Continue exploring topics related to this article

Upside-Down Architecture
JANUARY 20TH, 2026
Yannick Utard

Upside-Down Architecture

Architecture, Engineering

Most analytics queries scan less than 100MB, yet traditional architectures still assume compute must live in a remote warehouse. We explore a hybrid model where compute moves between our servers and your local machine, powered by DuckDB and open table formats.

READ ARTICLE
Lessons from Search
JANUARY 13TH, 2026
Sylvain Utard

Lessons from Search

Performance, Architecture, Engineering

Real-time analytics systems face the same small-file problem that search engines solved decades ago. DuckLake's new tiered compaction primitives bring battle-tested merge strategies to streaming analytics, making low-latency ingestion sustainable.

READ ARTICLE
Under the Hood: Agents
JULY 15TH, 2025
Sylvain Utard

Under the Hood: Agents

AI Agents, Architecture, Engineering

Altertable agents think ahead. Powered by custom lakehouse and MCP, they monitor, investigate, and act on your data autonomously.

READ ARTICLE
Stop Batching Analytics
DECEMBER 30TH, 2025
Sylvain Utard

Stop Batching Analytics

Analytics, Architecture, Performance

Why we're forcing analytics through complex batch pipelines when append-only data should work like logs. The warehouse constraint that stopped making sense.

READ ARTICLE
From STDIO to OAuth
OCTOBER 21ST, 2025
Sylvain Utard

From STDIO to OAuth

Engineering, Open Source

How MCP evolved from local stdio to OAuth 2.0 for cloud-scale AI, using Dynamic Client Registration for secure agent access.

READ ARTICLE
Altertable Logo

Wake Up To Insights

Join product, growth, and engineering teams enabling continuous discovery