---
title: How To Use NDJSON Streams with can-connect
description: Learn how to improve your app’s performance and user experience with can-connect and NDJSON streams.
image: https://www.bitovi.com/hubfs/Bitovi_July_2016_Theme/Images/canjs-background-blue.gif
---

- ![AI implementation](https://www.bitovi.com/hubfs/AIConsultingIcon.svg)
  
  [AI implementation](https://www.bitovi.com/services/ai-consulting)
- ![Systems engineering](https://www.bitovi.com/hubfs/icon%20-%20backend.svg)
  
  [Systems engineering](https://www.bitovi.com/services/systems-engineering-consulting)
- ![Project Management](https://www.bitovi.com/hubfs/icon%20-%20PM.svg)
  
  [Project Management](https://www.bitovi.com/services/agile-project-management-consulting)
- ![Product Design](https://www.bitovi.com/hubfs/icon%20-%20design.svg)
  
  [Product Design](https://www.bitovi.com/services/product-design-consulting)
- ![Frontend development](https://www.bitovi.com/hubfs/icon%20-%20frontend.svg)
  
  [Frontend development](https://www.bitovi.com/services/frontend-development-consulting)
- [View more
  
  →
  
  ](https://www.bitovi.com/digital-consulting-services)

We're Experts in...

- [JavaScript](https://www.bitovi.com/services/frontend/javascript-consulting)
- [AI training](https://www.bitovi.com/ai-training-for-software-engineers)
- [Angular](https://www.bitovi.com/services/frontend/angular-consulting)
- [Design systems](https://www.bitovi.com/services/axure-figma-migration)
- [React](https://www.bitovi.com/services/frontend/react-consulting)
- [Temporal](https://www.bitovi.com/services/backend/temporal-consulting)
- [React Native](https://www.bitovi.com/services/frontend/react-consulting/react-native)
- [Node.js](https://www.bitovi.com/services/backend/nodejs-consulting)

Showcase

![Yum! Brands](https://www.bitovi.com/hubfs/yum-showcase-link-1.png)

[View case study](https://www.bitovi.com/en/bitovi-yum-case-study)

More Projects

- [![Levi's](https://www.bitovi.com/hubfs/levis.svg)](https://www.bitovi.com/web-application-consulting-work/levis-ecommerce-responsive-redesign)
- [![Christie's International Real Estate](https://www.bitovi.com/hubfs/christies.svg)](https://design.bitovi.com/christies)
- [![BAFS](https://www.bitovi.com/hubfs/bafs.svg)](https://www.bitovi.com/ux-design-consulting/ux-case-studies/bafs-ppp)
- [View more
  
  →
  
  ](https://www.bitovi.com/our-software-consulting-work)

Open Source Tools

We build powerful tools and open source them to support the community.

[See what we've built →](https://www.bitovi.com/open-source)

- [![Blog](https://www.bitovi.com/hubfs/icon%20-%20blog.svg)
  
  BlogWe post about delivering products and solving problems.
  
  ](https://www.bitovi.com/blog)
- [![Partnerships](https://www.bitovi.com/hubfs/Handshake-1.svg)
  
  PartnershipsLearn about Bitovi's technology partners
  
  ](https://www.bitovi.com/partnerships)
- [![Academy](https://www.bitovi.com/hubfs/icon%20-%20academy%20(4).svg)
  
  AcademyFree courses to build delivery skills
  
  ](https://www.bitovi.com/academy)
- [![Open source tools](https://www.bitovi.com/hubfs/icon%20-%20open%20source.svg)
  
  Open source toolsUse or contribute to our community
  
  ](https://www.bitovi.com/open-source)

Let's Connect

- [![Discord](https://www.bitovi.com/hubfs/DiscordLogo.svg)
  
  Discord
  
  ](https://discord.gg/J7ejFsZnJ4)
- [![LinkedIn](https://www.bitovi.com/hubfs/LinkedinLogo.svg)
  
  LinkedIn
  
  ](https://www.linkedin.com/company/bitovi/)
- [![GitHub](https://www.bitovi.com/hubfs/GithubLogo.svg)
  
  GitHub
  
  ](https://github.com/bitovi/)

![Eggbot](https://www.bitovi.com/hubfs/build_assets/bitovi-limbo-cms-react/338/js_client_assets/assets/eggbot-LTGhdSGL.png)

Name *

Work Email *

Phone

What's your project?

Send

### Contact Us

(312) 620-0386contact@bitovi.com

 July 18, 2017

# How To Use NDJSON Streams with can-connect

 Learn how to improve your app’s performance and user experience with can-connect and NDJSON streams.

![The Bitovi Team](https://www.bitovi.com/hubfs/TheBitoviTeam%20(1).png)

 The Bitovi Team

Share:

[![Twitter](https://www.bitovi.com/hubfs/limbo-generated/_astro/twitter-white.os3xLc3C_Z2nW4or.svg) ](https://twitter.com/intent/tweet?text=) [![Reddit](https://www.bitovi.com/hubfs/limbo-generated/imgs/icons/reddit.png) ](http://reddit.com/submit?url=)

In [our previous post](https://www.bitovi.com/blog/faster-page-loads-how-to-use-ndjson-to-stream-api-responses), we talked about how to improve an app’s performance and user experience by incrementally updating our app’s UI as we received a stream of data from our API. Our example app was built on the [Fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API) and [can-ndjson-stream](https://canjs.com/doc/can-ndjson-stream.html) to get a [ReadableStream](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream) of [NDJSON](http://ndjson.org/) and render the stream in our app.

If you’re using [can-connect](https://canjs.com/doc/can-connect.html), there’s an even easier way to render a stream of data in your app—with [can-connect-ndjson](https://canjs.com/doc/can-connect-ndjson.html)! This post will demonstrate how to configure this behavior to incrementally load an API response that’s streamed by your server.

![incremental NDJSON rending vs. JSON object](https://camo.githubusercontent.com/1f6cdb22fdcdfae0fa244410f36a684f34aadf9d/68747470733a2f2f676973742e6769746875622e636f6d2f6267616e646f2f39336261396339613462653639613837366133633162663464323766386132632f7261772f663834336535633161613839666637393661346561623133616136383231353765383831363562642f6e646a736f6e2d73747265616d2d6a736f6e2e676966)

## Getting started with can-connect-ndjson

[can-connect-ndjson](https://canjs.com/doc/can-connect-ndjson.html) is a [can-connect](https://canjs.com/doc/can-connect.html) behavior that can receive, transform, and render lines of a server response body as a stream on the client.

If you are familiar with [can-connect](https://canjs.com/doc/can-connect.html), then you have probably used behaviors in the past to connect your model with the HTTP layer. If you’re not familiar, it looks something like this:

```
const connect = require("can-connect");
const DefineList = require("can-define/list/list");
const DefineMap = require("can-define/map/map");

//Require behaviors for connection
const urlBehavior = require("can-connect/data/url/url");
const constructorBehavior = require("can-connect/constructor/constructor");
const mapBehavior =  require("can-connect/can/map/map");

const behaviors = [urlBehavior, constructorBehavior, mapBehavior];

// Define model
const Todo = DefineMap.extend("Todo", {id: "number", name: "string"}); 
Todo.List = DefineList.extend("TodoList", {"#": Todo});

// Create connection passing behaviors and options
Todo.connection = connect(behaviors, {
    Map: Todo,
    List: Todo.List,
    url: "/todos"
});

//GET request for a list of todos from "/todos"
const todosPromise = Todo.getList({});
```

### Add the can-connect-ndjson behavior to support streamable responses

[can-connect-ndjson](https://canjs.com/doc/can-connect-ndjson.html) works by extending the [Data](https://canjs.com/doc/can-connect.html#DataInterface) and [Instance](https://canjs.com/doc/can-connect.html#InstanceInterface) interfaces to work with streamed NDJSON data to create instances of the data model. Simply require the behavior and pass the optional NDJSON endpoint if your backend serves NDJSON from an endpoint other than your default `url` endpoint.

**Steps:**

1. Require the `can-connect-ndjson` behavior
2. Add the `can-connect-ndjson` behavior to the`behaviors` array
3. Pass the behaviors into the connection
4. [Optional] Pass the NDJSON endpoint if it differs from your default `url`

The `todosPromise` will resolve with an empty list once a connection is established, then `todosPromise.value` will be updated with the first `Todo` instance once the first line of NDJSON is received. Each `todo` instance will be a line of the NDJSON.

```
const connect = require("can-connect");
const DefineList = require("can-define/list/list");
const DefineMap = require("can-define/map/map");

//Require behaviors for connection
const urlBehavior = require("can-connect/data/url/url");
const constructorBehavior = require("can-connect/constructor/constructor");
const mapBehavior =  require("can-connect/can/map/map");
//Step 1: Require the NDJSON behavior.
const ndjsonBehavior = require("can-connect-ndjson");
//Step 2: Add can-connect-ndjson (ndjsonBehavior) to the behaviors array.
const behaviors = [urlBehavior, constructorBehavior, mapBehavior, ndjsonBehavior];

// Define model
const Todo = DefineMap.extend("Todo", {id: "number", name: "string"}); 
Todo.List = DefineList.extend("TodoList", {"#": Todo});

//Step 3: Create the connection by passing behaviors and options
Todo.connection = connect(behaviors, {
    Map: Todo,
    List: Todo.List,
    url: "/todos",
    ndjson: "ndjson/todos" //Step 4: [optional] specify the NDJSON API endpoint
});

//GET request for NDJSON stream of todos from "/ndjson/todos"
const todosPromise = Todo.getList({}); 
```

### There you have it! Let’s render it incrementally.

You have now configured your `can-connect` connection to receive stream responses from your API and create instances of the data model. Now use the model with a template:

```
const stache = require("can-stache");

const template = "<ul>{{#each todosPromise.value}}<li>{{name}}</li>{{/each}}</ul>";
const render = stache(template);

document.body.append(render({todosPromise: todosPromise}));
```

**Remember:** once a connection is established, `todosPromise.value` will be an empty array until the first line of NDJSON data is received, then the NDJSON lines will be deserialized into `Todo` instances and pushed into your array.

## Conditional rendering based on state

In a real-world environment, we not only need to render the state of the `List`model, but also the state of the stream so that we can communicate to our users whether or not to expect more data or if there was an error. To do this, we have access to the following state properties:

**Promise state**, the state of the initial connection to the stream:

- `isPending`—the list is not available yet
- `isRejected`—an error prevented the final list from being determined
- `isResolved`—the list is now available; note that the list is still empty at this point

**Streaming state**, available on the list after the promise is resolved to a stream:

- `isStreaming`—the stream is still emitting data
- `streamError`—an error that has prevented the stream from completing

Here is an example of a template capturing the various states and rendering conditionally for an improved user experience. In this example, we still pass `todosPromise` to render our template:

```
{{#if todosPromise.isPending}}
  Connecting
{{/if}}

{{#if todosPromise.isRejected}}
  {{todosPromise.reason.message}}
{{/if}}

{{#if todosPromise.isResolved}}
    <ul>
        {{#each todosPromise.value}}
            <li>{{name}}</li>
        {{/each}}
    </ul>
    {{#if todosPromise.value.isStreaming}}
        Loading more tasks
    {{else}}
        {{#if todosPromise.value.streamError}}
            Error: {{todosPromise.value.streamError}}
        {{else}}
            {{^todosPromise.value.length}}
                <li>No tasks</li>
            {{/todosPromise.value.length}}
        {{/if}}
    {{/if}}
{{/if}}
```

## Next steps

Find more details about using [can-connect](https://canjs.com/doc/can-connect.html) with NDJSON streams in the [can-connect-ndjson docs](https://canjs.com/doc/can-connect-ndjson.html).

If you use this new module, let us know on our [forums](http://forums.donejs.com/c/canjs) or [Gitter chat](https://gitter.im/donejs/donejs)! We’d love to hear about your experience using NDJSON streams with [can-connect](https://canjs.com/doc/can-connect.html).

We’re working on even more [streamable app features for DoneJS](https://github.com/donejs/donejs/issues/834). Keep up with the latest in the community by [following us on Twitter](https://twitter.com/donejs)!

[![Tag for open source](https://www.bitovi.com/hubfs/limbo/icons/tag.svg) open source ](https://www.bitovi.com/blog/topic/open-source)[![Tag for development](https://www.bitovi.com/hubfs/limbo/icons/tag.svg) development ](https://www.bitovi.com/blog/topic/development)[![Tag for canjs](https://www.bitovi.com/hubfs/limbo/icons/tag.svg) canjs ](https://www.bitovi.com/blog/topic/canjs)

 Previous Post

![](https://www.bitovi.com/hs-fs/hubfs/Bitovi_July_2016_Theme/Images/canjs-background-blue.gif?height=117&name=canjs-background-blue.gif) [ Faster Page Loads: How to Use NDJSON to Stream API Responses ](https://www.bitovi.com/blog/faster-page-loads-how-to-use-ndjson-to-stream-api-responses)

  

 Next Post

![](https://www.bitovi.com/hs-fs/hubfs/checlist-rainbow.jpg?height=117&name=checlist-rainbow.jpg) [ The Designer's Checklist for Reviewing Pull Requests ](https://www.bitovi.com/blog/designer-pr-checklist)

```json
{
  "@context" : "http://schema.org",
  "@type" : "Organization",
  "address" : {
    "@type" : "PostalAddress",
    "addressCountry" : "United States",
    "addressLocality" : "Libertyville",
    "addressRegion" : "IL",
    "postalCode" : "60048",
    "streetAddress" : "1134 Pine Tree Lane "
  },
  "alternateName" : "Bitovi",
  "areaServed" : {
    "@type" : "GeoCircle",
    "geoMidpoint" : {
      "@type" : "GeoCoordinates",
      "latitude" : "41.8781",
      "longitude" : "87.6298"
    },
    "geoRadius" : "5000 km"
  },
  "description" : "Bitovi is a UX, UI design and front-end JavaScript development consulting company",
  "email" : "contact@bitovi.com",
  "image" : "https://www.bitovi.com/hubfs/bitovi-logo-x2.png",
  "logo" : "https://www.bitovi.com/hubfs/bitovi-logo-23-1.svg",
  "mainEntityOfPage" : {
    "@id" : "https://www.bitovi.com/blog/how-to-use-ndjson-streams-with-can-connect",
    "@type" : "WebPage",
    "description" : "Learn how to improve your app’s performance and user experience with can-connect and NDJSON streams."
  },
  "naics" : "541511",
  "name" : "Bitovi Web App Consulting",
  "sameAs" : [ "https://www.facebook.com/BitoviLLC/", "https://twitter.com/bitovi", "https://www.linkedin.com/company/bitovi" ],
  "telephone" : "312-620-0386",
  "url" : "http://bitovi.com"
}
```

```json
{
  "@context" : "http://schema.org",
  "@type" : "BlogPosting",
  "author" : {
    "@type" : "Person",
    "name" : "The Bitovi Team"
  },
  "dateModified" : "July 18, 2017, 3:55:33 PM",
  "datePublished" : "2017-07-18 15:55:33",
  "description" : "Learn how to improve your app’s performance and user experience with can-connect and NDJSON streams.",
  "headline" : "How To Use NDJSON Streams with can-connect",
  "image" : {
    "@type" : "ImageObject",
    "url" : "https://www.bitovi.com/hubfs/Bitovi_July_2016_Theme/Images/canjs-background-blue.gif"
  },
  "publisher" : {
    "@type" : "Organization",
    "logo" : {
      "@type" : "ImageObject",
      "url" : "https://www.bitovi.com/hubfs/bitovi-logo-23-1.svg"
    },
    "name" : "Bitovi"
  }
}
```