Skip to content

Aquent | DEV6

Generic selectors
Exact matches only
Search in title
Search in content
Search in posts
Search in pages

What is JAMstack and Scully?

Written by: Kevin Wang

JAMstack stands for JavaScript, APIs, and Markup. The idea of JAMstack is to run websites without the need for server-side code, which results in faster page loads. You might be thinking, about what about APIs? Does this mean my site can’t perform API calls? That’s where Scully comes in handy.

Scully is a static site generator for Angular projects, it adds an additional step to the build process to generate the required static pages. Also, Scully can cache your API calls during the build process, which means making the HTTP request and storing the results locally.

When using Scully, you’re essentially adding an additional step to the build process that compiles and builds the required static pages, in addition to the ability to generate the required code with the help of ‘plugins’ to get started.

If you want to read more in depth about JAMstack, I strongly recommend you to read my colleague Shane’s blog here.

Getting started with Scully — the static part

Scully can sit on top of any existing Angular project and can easily be added via the CLI.

To add Scully to a project, simply use the following commands while in the root folder of your project.

ng add @scullyio/init

To build and run with Scully, use the following commands:

You need to build the Angular project before Scully.

ng build && npm run scully

Viola! You’ve just converted your existing Angular app into a JAMstack, static (but still data dynamic capable) site. You can find your Scully build version of the project inside your ./dist/static folder.

Now it’s time to serve it.

npm run scully serve 

This will launch two servers, the first one is for the Angular project and the second one is the result of the Scully build. You can run them side by side for easy comparison.

Getting started with Scully — the generator part

The perk with Scully is that it allows us to generate a blog using Angular’s generation schematics. What this means is that you can use ng generate to create Scully templates.

To generate a simple blog, use the following command:

ng g @scullyio/init:blog

This command will create a blog module with the required routes. You’ll also get a blog folder with some markdown files. Every time Scully builds, the markdown files will be rendered into HTML.

To create your first post, use the following command:

ng g @scullyio/init:post --name="the-first-post"

If you look at your blog folder, you’d find a file called with some markdown content inside.

When you want to run the blog, you’ll need to build it because Angular can’t read markdown and the contents of the post will need to be compiled into HTML. Every time you build, the markdown will be converted into the necessary code and cut down on server response time because it’s serving from generated static files.

To serve your Scully site, run the following command:

ng build && npm run scully serve

NOTE: if you don’t see your newly created blog, you may need to run the following command to discover the new routes.

npm run scully -- --scanRoutes

When you open the markdown file, it should look something like this.

title: the-first-post
description: 'blog description'
published: false
    - ___UNPUBLISHED___kc6mrgm7_j38OSEqftuNg1AN4iHojl3KRmnXP0gP7

# the-first-post

The slugs is just a temporary place holder for you to share the blog with someone else before it goes live. If you’re satisfied with the blog, you can go ahead and remove the slugs and change published to true;

After you made any changes, you need to build Scully again like so.npm run scully

Now let’s serve it and see it live:

npm run scully serve

Navigate to:


But since we don’t have the route configure yet, there’s no other way to see the blog other than typing the full URL of it, so let’s just do that.

Configure Scully Route:

First, let’s create something to hold all the posts. We also need to initialize Scully Routes Service in the constructor. Then in the ngOnInit life cycle hook to make usage of the service we just added.

export class BlogComponent implements OnInit {
  posts$: Observable<ScullyRoute[]>;

  ngOnInit() {
    this.posts$ = this.scullyRoutesService.available$;

    private router: Router,
    private route: ActivatedRoute,
    private scullyRoutesService: ScullyRoutesService) {

Finally, in your template, create a list to showcase all your post. We need to check if published is true because posts$ contains all the routes that Scully can find. For example, your home route, your about route, etc…

<ul *ngFor="let post of posts$ | async">
  <li *ngIf="!!post.published">
    <a [routerLink]="post.route">{{ post.title }}</a>

Once Again, before you can see the change, you’ll need to do this.

Ng build && npm run scully && npm run scully serve

Final thoughts

Scully might not seem like a big deal right now, but you can already see its potential. Scully provides a way for Angular developers to support more traditional content-oriented sites, and the Internet is built on content after all.