Back

Announcing Nitric version 1.0.0!

Nitric version 1.0.0 newsletter banner
Jye CuschJye Cusch

Jye Cusch

11 min read

We’re excited to announce the official release of version 1.0.0 of the Nitric framework! Our team has a number of enhancements to share with you that solidify the framework.

Nitric’s vision is to empower software development teams to be highly productive while building portable, customizable cloud applications – innovative apps that run anywhere with the best technology. As we've developed the framework and learned from early users, we’ve been fueled by making cloud development and deployment even faster and more manageable. Nitric removes blockers around manual infrastructure decision-making, setup and troubleshooting, so that you can prototype, get to market and get the benefits of serverless. Infrastructure is automatically generated so you get consistent deployments that always match the current version of your application.

With version 1.0.0, we're making it even easier for developers to learn Nitric and get started. There are several enhancements to the live output of Nitric that show what the framework is handling for you so you can move confidently through development and deployment. And to scale DevOps control, we've made significant improvements to the experience of customizing and extending Nitric for your infrastructure needs, so more than ever you have the freedom to switch clouds and services when you want.

Check out the key features and enhancements that are now available below. We can’t wait to hear your feedback and work with you on your next Nitric project.

Improved developer experience

Great DX isn't just about making life easier; it also leads to higher quality products and better morale.

We know the quality of software improves significantly when the right tools and resources are available. Having access to efficient tools, clear documentation, and a streamlined development process enables developers to concentrate on coding, rather than struggling with environment challenges.

Recent polling and interactions with the community have revealed that teams can burn out by spending 60% or more of their time on debugging, setting up a local env and infrastructure related activities. V1 is here to improve on this.

So often, if you’re a developer, you have to wait for feedback, You get interrupted. You’re constantly stalled. You have to figure out a cumbersome process. But if, instead, you can collaborate quickly, have no interruptions, use intuitive technologies, and stay in the flow—that’s when you can problem-solve, be creative, and get work done, which will benefit the team and entire organization.

Providing an excellent DX has always been a priority for Nitric. In v1 we’ve continued this work, with a particular focus on our CLI user experience. We’ve made sure that the Nitric CLI provides consistent, detailed user output. The changes include new detailed live output of what Nitric is doing for you; you can see these details as you go, so infrastructure provisioning is transparent. We’ve also made sure that the CLI works just as well for teams using custom providers (see more about how custom providers are even easier to use down below!), showing you deployment of resources created by custom providers in addition to those created by standard providers.

Example Nitric Up

Visualize your app’s architecture

In this release, we've also introduced a crystal-clear view of the resources being created within your Nitric applications. Understanding the relationship between resources and IAM (Identity and Access Management) roles and policies is crucial for robust cloud security. We've made it easier to see how services and resources interact, aiding in enforcing least privilege security.

You’ll notice updates in both the Nitric local dashboard during development, and the CLI during deployment.

Example Architecture Diagram

One of the primary use cases for these enhancements is the availability of immediate feedback. You can now see a live visual representation of your cloud infrastructure as you build. This instant visualization aids in comprehending complex cloud environments, making it easier to reason about what you’re actively building and grasp the scale and structure of deployed resources. For example, it's now easy to spot in real time when there are rogue/detached resources being deployed, cyclic dependencies when triggering events, or even simple optimizations like reusing services/topics/buckets etc. to save on cost.

Users of Nitric have expressed challenges visualizing the infrastructure that runs their application. This feature directly addresses this gap, providing a tangible, visual context to abstract code.

The architecture visualizations also facilitate team collaboration. In many teams, the technical complexity of cloud infrastructure can create barriers between those who write the code and those who manage it. With real-time visualization, Nitric now provides a common visual language that all team members can understand, regardless of their technical depth.

We’d also like to call out that this technology serves as an educational tool for new team members. Learning what resources to deploy on the cloud to implement features like scheduled services and real time messaging can be challenging. Real-time visualization significantly flattens the learning curve, making it easier for newcomers to understand and engage with cloud infrastructure.

Explore the architecture visualizations in Nitric’s local dashboard.

Extend or customize with less work

Nitric has always facilitated consistent deployments, allowing for uniform configuration of tagging, roles, policies, and more across all your projects using our official Nitric providers. These are a great fit for many teams, but not for all situations. With that in mind we’ve also built the framework with extensibility and customization available for teams with different needs.

While customization was supported in previous versions, it's now significantly easier. With v1, rather than creating custom providers from the ground up, Nitric now offers the flexibility to extend or modify parts of the official Nitric providers.

Providers are individual plugins composed of logic to deploy the resources (APIs, secrets, schedules, etc.) that your application requires to run on the cloud you target for deployments (AWS, GCP, Azure, etc.). They also take care of handling SDK calls during runtime.

The deployment components of the Nitric standard providers are built using Pulumi. For example, when you declare a resource like a storage bucket with the following code:

const images = bucket('image').for('reading')

The deployment provider takes the request for a bucket and provisions it on the cloud you've targeted in your nitric stack configuration.

In the case of AWS, this would be an S3 bucket and a simplified version of the code would look like this:

func (a *NitricAwsPulumiProvider) Bucket(ctx *pulumi.Context, parent pulumi.Resource, name string, config *deploymentspb.Bucket) error {
	opts := []pulumi.ResourceOption{pulumi.Parent(parent)}

	bucket, err := s3.NewBucket(ctx, name, &s3.BucketArgs{
		Tags: pulumi.ToStringMap(common.Tags(a.stackId, name, resources.Bucket)),
	}, opts...)
	if err != nil {
		return err
	}

	a.buckets[name] = bucket

	if len(config.Listeners) > 0 {
		notificationName := fmt.Sprintf("notification-%s", name)
		notification, err := createNotification(ctx, notificationName, &S3NotificationArgs{
			StackID:   a.stackId,
			Location:  a.region,
			Bucket:    bucket,
			Lambdas:   a.lambdas,
			Listeners: config.Listeners,
		}, opts...)
		if err != nil {
			return err
		}

		a.bucketNotifications[name] = notification
	}

	return nil
}

For Azure:

func (p *NitricAzurePulumiProvider) Bucket(ctx *pulumi.Context, parent pulumi.Resource, name string, config *deploymentspb.Bucket) error {
	var err error
	opts := []pulumi.ResourceOption{pulumi.Parent(parent)}

	p.buckets[name], err = storage.NewBlobContainer(ctx, ResourceName(ctx, name, StorageContainerRT), &storage.BlobContainerArgs{
		ResourceGroupName: p.resourceGroup.Name,
		AccountName:       p.storageAccount.Name,
	}, opts...)
	if err != nil {
		return err
	}

	for _, sub := range config.Listeners {
		err = p.newAzureBucketNotification(ctx, parent, name+sub.GetService(), sub)
		if err != nil {
			return err
		}
	}

	return nil
}

And for GCP:

func (p *NitricGcpPulumiProvider) Bucket(ctx *pulumi.Context, parent pulumi.Resource, name string, config *deploymentspb.Bucket) error {
	var err error
	opts := append([]pulumi.ResourceOption{}, pulumi.Parent(parent))

	resourceLabels := common.Tags(p.stackId, name, resources.Bucket)

	p.buckets[name], err = storage.NewBucket(ctx, name, &storage.BucketArgs{
		Location: pulumi.String(p.region),
		Labels:   pulumi.ToStringMap(resourceLabels),
	}, p.WithDefaultResourceOptions(opts...)...)
	if err != nil {
		return err
	}

	for _, listener := range config.Listeners {
		if err := p.newCloudStorageNotification(ctx, parent, name, listener); err != nil {
			return err
		}
	}

	return nil
}

Accessing files in your application requires a runtime provider, which is implemented directly using the cloud APIs. So when your code attempts to read a file:

images.file('cat.png').read()

The runtime provider will take this request and call the AWS API something like the following:

resp, err := s.s3Client.GetObject(ctx, &s3.GetObjectInput{
  Bucket: s3BucketName,
  Key:    aws.String(req.Key),
})
if err != nil {
  if isS3AccessDeniedErr(err) {
    return nil, newErr(
      codes.PermissionDenied,
      "unable to read file, this may be due to a missing permissions request in your code.",
      err,
    )
  }
  // continued...
}

We again know which provider to use based on the nitric stack configuration, so equivalent code would be deployed for Azure or GCP

The advancements made in v1 mean that implementing your specific guardrails and settings requires minimal effort. It also means that you can customize your cloud and resource deployments without losing access to future provider updates from Nitric. The ability to adapt and overwrite existing providers both saves time but also ensures that your unique requirements are met without compromising on the integrity of the standard deployment procedures.

We’re really excited about the possibilities this unlocks for teams to switch clouds and services without rewriting core code. This means significantly less risk in choosing cloud technologies, since you can easily swap out as requirements change.

Dive into the documentation for Nitric’s custom provider SDK.

More updates based on developer feedback

There are a number of additional improvements in version 1.0.0 as a result of the great community feedback we’ve received:

  • Collections are now key/value stores We know that most Nitric users have a 3rd party database to use alongside Nitric, so we’ve transitioned our Collections feature to Key/Value stores to best facilitate the way this feature has been used by users. Making this change also greatly reduces the amount of code needed for the feature, reducing the maintenance burden of using Nitric. Read more about this in the key/value documentation.
  • New Dart SDK (experimental) For users building mobile apps, Dart is often the language of choice. With version 1.0.0 we’re adding support for Dart to meet user requests! Use the same language for both front-end and back-end development, creating a unified stack.
  • Enhanced local schedules In version 1.0.0 Nitric now makes it possible to run schedules locally in real-time in addition to manually triggering them on-demand. Local development experience is always a priority for us, and this enhancement means that you test your schedules without waiting, as well as test realistic scenarios with the proper firing. See how in the schedules documentation.
  • Multi-subscription We’ve updated the Nitric Topics feature to allow subscribing to topics multiple times in a single service. Subscribing a service to multiple topics provides flexibility, code organization and a centralized approach to event handling. It can be particularly beneficial in scenarios where multiple topics share common functionality or where dynamic event handling is required. Read more in the Topics documentation.
  • Simplified messaging Messaging resources (Queues and Topics) have both been simplified in version 1.0.0, allowing for publishing/enqueueing of plain object payloads without the need to specify payload types or IDs. While these fields can still be included they're no longer imposed by default.

What’s next with Nitric

We hope you love the new features in Nitric v1, and we’re really looking forward to your feedback as you start developing with it. Start a chat with us any time on Discord.

We’re already planning and starting development on a few features to further the enhancements in v1, so check out our roadmap and let us know what you think. Stay tuned for:

Thanks for being part of Nitric’s journey! As we work to reach more folks with the framework, we’d really appreciate a GitHub star and your support in spreading the word about what we’re building.

Previous Post
4 Lessons Learned from Building Microfrontends
Next Post
Automated Cloud Infrastructure Deployment with GitHub Actions and Nitric