I've already covered building a static dashboard with Cube and Chart.js in this tutorial. Now, I’m going to show you how to dynamically change the underlying chart’s data based on the user’s input.
We’ll let the user pick a date range and based on that, reload the chart. When a user picks a new set of dates, a new request will be sent to the Cube API. The Cube server will generate new SQL code, execute it against the database, and send the result back to the client. And finally, the client re-renders a chart with the new data.
Here is a CodeSandbox demo of what we are going to build. You can click "Open in Editor" to check the source code.
Updated for 2026: This walkthrough now uses the current Cube JavaScript client and Chart.js 4, and the dynamic example handles overlapping requests and failed loads. The embedded CodeSandbox remains a snapshot of the original example. For a broader introduction to Chart.js 4, start with the Chart.js v4 tutorial.
Setting up an API
We're going to create a new Cube app and connect it to a cloud-based Postgres dataset.
First, make sure you have Docker installed on your machine. The current Cube Core getting-started guide covers the complete self-hosted setup and the equivalent Cube Cloud path.
Second, create new a folder for your Cube app and navigate to it:
Then, create a new docker-compose.yml file with Cube configuration. We'll use environment variables for configuration and instruct Cube to connect to a publicly available cloud-based Postgres dataset:
The last step is to run Cube.js:
Now you can open localhost:4000 in your browser. You will see Developer Playground, a companion tool for developing and querying your Cube data model.
We're going to use it to generate the data schema for the database. Please navigate to the Schema tab, select the public schema, and click "Generate Schema". Great! Now you can navigate to the Build tab to play around with the data:

For the frontend portion of this tutorial, we are going to use a Cube API deployed to Cube Cloud at https://awesome-ecom.gcp-us-central1.cubecloudapp.dev/cubejs-api/v1.
Simple Chart
We'll use CodeSandbox, an online editor for rapid web development, to build the front-end app. You can check out the final source code and the demo app. Feel free to fork it and play around.
We are going to use the Vanilla template from CodeSandbox. To keep things simple, we'll not add any framework, such as React or Vue.

The first step is to include the Cube.js client and Chart.js libraries. Insert the following code inside the dependencies key of the package.json file. It should look like this:
To initialize the Cube.js client, we need to pass an API URL along with the secret. We'll also import the libraries we've just added. Add these lines to the index.js file:
Once the client is initialized, we can request data from the API and visualize it. The load function accepts a query, which is a plain JavaScript object, and returns a promise. You can learn more about the query format in the docs.
We are loading Orders.count, which is grouped by the created day to plot as a line chart. To make this code work, we need to make a couple of things. First, add the <canvas> tag to the inside the <body> in the index.html file:
Next, we need to define the chartJsData function, which should accept a resultSet returned from Cube.js and format it for Chart.js. Add this to the index.js file:
That is all we need to load the data and visualize it as a static line chart:

Dynamic Data
Next, we’re going to add a date range picker and load data dynamically based on the date range selected by the user.
Let's add the flatpickr dependency we'll be using as a lightweight date picker in the package.json file. It should look like this:
Next, let's import this library in the index.js file:
Next, let’s wrap the code to render a chart into the drawChart function, which accepts a start date and an end date. A user can change the range again before the previous API call finishes, so we also track the latest request. That prevents a slower, older response from overwriting the chart with stale data.
Besides making the dateRange dynamic, we save the current chart in the chart variable so we can update it rather than create a second Chart.js instance. latestRequest makes the last selected range authoritative, while the catch block gives the reader a visible failure state instead of leaving an apparently frozen chart.
Finally, we can add an input to the index.html file and make it a date range picker. Let's add a CSS import inside the head and an input inside the body:
In the index.js file, after the drawChart function:
That is it! Now we have a fully working dynamic and interactive chart.

And here's an interactive CodeSandbox that we've built. You can select different dates from the date picker and see how the chart is changing.
This example keeps the presentation deliberately small: one governed measure, one date filter, and one chart. The same semantic model can also serve self-service dashboards and AI agents without giving each interface a separate definition of Orders.count. When you are ready to move the prototype onto that shared foundation, Try Cube for free.
