Customers

Share this article

Why we stopped hardcoding dashboards (and moved to configuration-based widgets instead)

Here's how we shifted to a JSON-driven widget system for our analytics and why it matters for how fast we ship.

Analytics dashboards are crucial for IT leaders to keep a bird’s eye view of their service operations. However, what starts as simple charts and tables, quickly turn into a sprawl of one-off components that nobody wants to touch.

These dashboards then become brittle, slow to change, and tightly coupled to the frontend codebase. Every small tweak requires a deployment or a new component. The dashboards that were meant to give IT teams speed, on the contrary, slows them down.

That’s why we decided to rearchitect the system around building analytics dashboards; the core idea being to stop hardcoding widgets in React and start describing them with JSON configuration instead.

This post is about the thinking behind the approach, and why it matters beyond just clean code.

The switch from dashboard components to configuration

If you’ve ever looked under the hood of a dashboard, the code usually looks something like this:  

  • A parent <Dashboard> component  
  • Followed by a growing list of hardcoded children — <RevenueChart />, <ActiveUsersChart />, <ErrorRateWidget /> — each one a bespoke piece of UI.  

While this does work, each time a customer requests for a new widget or different time ranges to an existing chart, we need to tinker the frontend code, review, and deploy it; which is not only time consuming but quickly turns into a pile of bespoke components, each with its own layout logic and assumptions.

The new system flips this around.  

Instead of writing a component for every widget, we describe each widget as a small JSON object:

{ 
  "id": "api_error_rate", 
  "title": "API Error Rate", 
  "description": "Error percentage in the last 24 hours", 
  "type": "line-chart", 
  "query": "errors_over_time", 
  "timeRange": "24h" 
} 

A lightweight renderer reads this configuration and maps it to the right component from a registry. The configuration says what to show. The components know how to show it. That's the whole idea.

Adding a new widget type means building one component and registering it. Adding a new instance of an existing type means adding a few lines of JSON. No page-level changes, no deployment for a label tweak, no risk of breaking something unrelated.

We applied the same principle to layout by turning widget positionings into configurations, powered by a responsive grid system. And we layered TypeScript on top so that invalid configurations fail at compile time rather than in production.  

My detailed post here walks you through all the code changes we made in depth.

Why this matters for how we ship

Here's where it gets interesting beyond the architecture.

We've built the Atomicwork platform from the ground up with intelligence at every layer, and our customers — IT leaders, service desk managers, CIOs — rely on that speed which traditional ITSM tools fail to offer.

That same principle applies to how we build the product itself. When our engineering team can ship a dashboard change in minutes instead of a sprint cycle, the compounding effects are real. Product can experiment with new metrics faster to improve customer-facing analytics. And when AI-generated insights need a new surface to live on, we don't need to go through a whole UI build cycle — we just add configuration.

When our customers as IT teams are under pressure to deliver more support, more visibility, and more automation, every week we save internally is a week our customers benefit from sooner.

Zooming out to see the broader pattern

Our specific implementation of JSON config, widget registries, and typed layouts is one version of a more general idea: separating what your UI shows from how it renders. If your dashboards are growing into a tangle of one-off components that are hard to extend and risky to change, this pattern is worth exploring.

We found it made our dashboards easier to build, easier to maintain, and fundamentally faster to evolve. For a company whose entire premise is helping IT teams move faster, that felt like the right kind of consistency.

I wrote up the full technical deep dive of the widget renderer, the registry pattern, the grid layout system, TypeScript safety, all of it on my personal blog here, if you want to implement something similar.

No items found.
Get a demo
Meet 100+
tech-forward CIOs
Sept 24, 2025
Palace Hotel, SF
Request an invite
Summarize with:

You may also like...

Rethinking ITSM analytics for the AI-native era: Frameworks and use cases
See how unified AI-native ITSM Analytics can guide automation, routing, and service team performance.
Context engineering: The secret weapon of CIOs architecting the future of IT
Engineering the right data can work as valuable context for your ITSM workflows and support to be faster and smarter.
Moving to Next.js 16 and React 19: Our major step in building a stable and secure platform
Why upgrading our frameworks to Next.js 16 and React 19 helped improve security, stability, and engineering velocity.

See Atomicwork in action now.