Fieldwork29
December 22, 2025

openJII’s Modern Architecture: Building an Open Science Platform for Photosynthesis Research

Launching a cutting-edge platform like openJII for photosynthesis research required a modern, robust architecture.

Dominik
Dominik VrbicTech Lead (openJII)

Launching a cutting-edge platform like openJII for photosynthesis research required a modern, robust architecture. openJII is designed to empower scientists and developers alike, enabling real-time data collection, analysis, and collaboration in an open-science environment. This article (part of our launch series) delves into the technical architecture of openJII – from its web and mobile front-ends to the backend services – and how these choices serve a global community of plant scientists.

Full-Stack Overview: Technology Choices

To create a seamless experience for both researchers and developers, openJII’s platform is built on a full-stack TypeScript architecture. Every layer of the stack leverages modern, open-source tools that emphasize scalability, maintainability, and developer productivity:

  • Web Frontend: Next.js (React framework) with Tailwind CSS for styling and Radix UI (via ShadCN) for accessible, polished components. This combination yields a fast, responsive web app with server-side rendering for good SEO and snappy performance.

  • Mobile App: React Native is used to deliver a cross-platform experience. Researchers can collect data or monitor experiments on the go with a native-feel app that shares design elements with the web interface (thanks to Tailwind styles and reusable components).

  • Backend API: NestJS (a Node.js framework inspired by OOP architecture) forms the backbone of our server. NestJS provides a modular, enterprise-grade architecture with built-in support for features such as dependency injection and declarative APIs, helping keep code organized and scalable. We paired NestJS with Drizzle ORM for type-safe database interactions and Zod schemas for runtime data validation. Together, these ensure that data moving through the system is consistent and validated at every step.

  • Database: PostgreSQL, a reliable open-source relational database, stores the platform’s core data (experimental results, user information, sensor readings metadata, etc.). Drizzle ORM’s migration and type generation features enable us to safely evolve the database schema while catching errors at build time.

  • Monorepo & Dev Tools: All components live in a single monorepo managed with pnpm and Turborepo, streamlining development. This setup allows shared TypeScript types and models between the frontend and backend – for example, the same Zod definitions ensure that the data shapes are consistent from the API to the UI. It also means a contributor can run one command to spin up the entire stack in development, making it easier for open-source collaborators to get involved.

By using TypeScript across the stack, from Next.js and React Native on the front-end to NestJS and Drizzle on the back-end, openJII achieves end-to-end type safety. This drastically reduces runtime errors and makes the code more approachable for new contributors (since one language is used almost everywhere). The emphasis on open-source frameworks (Next.js, NestJS, etc.) aligns with the platform’s open ethos – no proprietary lock-in, and a familiar environment for developers in the community.

Frontend: Next.js Meets Tailwind for a Responsive UI

The need for a fast and SEO-friendly interface drove the choice of Next.js for the web frontend. Next.js enables server-side rendering and static generation, so even complex data visualizations in openJII’s interface load quickly and can be indexed as needed. Coupled with Tailwind CSS, our developers could rapidly prototype and refine the UI while maintaining consistency. Tailwind utility classes ensure the design system remains cohesive across the platform, and Radix UI provides accessible components (such as menus, dialogs, and tooltips) that we customized with ShadCN’s library to deliver a modern look and feel.

On mobile, using React Native lets us maintain feature parity with the web app without duplicating effort. Researchers in the field – perhaps measuring photosynthesis on a remote farm or in a greenhouse – can use the openJII mobile app to upload sensor readings, annotate experiments, or review results in real time. React Native allows us to reuse business logic and even some UI elements from the web (thanks to shared libraries and Tailwind styling), while still delivering a smooth native experience on iOS and Android. For example, the device onboarding process (connecting a new photosynthesis sensor) will be available on both web and mobile.

Accessibility and responsiveness were key concerns for the frontends. Tailwind’s mobile-first approach and Next.js’s image optimization and routing helped ensure the platform is usable on various devices and network conditions. Whether a user is on a desktop in the lab or a smartphone in the field, they get a consistent, efficient interface. We believe this low-friction user experience is critical for adoption in the scientific community.

Backend: NestJS, Drizzle ORM, and Zod – A Robust Core

openJII’s backend is built with NestJS, which provides a scalable structure for our API and background services. NestJS’s built-in support for controllers, services, and modules enabled our team to separate concerns cleanly. For instance, data ingestion from IoT devices is handled in one module, while user management is in another – all configured to work together seamlessly under Nest’s framework. This modularity will help as the project grows, allowing contributors to focus on specific areas without breaking others.

Data integrity and correctness are paramount when scientists rely on the platform’s outputs. That’s why we use Zod alongside NestJS. Every piece of data that enters the system (be it from an API request or an IoT sensor reading) is validated against a Zod schema. This ensures that invalid or unexpected data is caught early and handled gracefully. For example, if a sensor erroneously sends a string where a number is expected, the Zod schema will flag it, and the system can reject or fix the data instead of crashing or, worse, silently corrupting a dataset.

Interacting with the database is done through Drizzle ORM, a modern TypeScript ORM that generates fully typed SQL queries. We chose Drizzle because it provides compile-time checked queries (no missing fields or incorrect types in SQL) while remaining lightweight. It doesn’t hide the fact that we’re using SQL and PostgreSQL – researchers who want to contribute to data processing logic can write or read straightforward TypeScript code that reflects actual SQL operations. This transparency aligns with openJII’s philosophy: everything, including data access, should be as transparent and open as possible. Moreover, Drizzle’s migration system helps us evolve the database schema with confidence, which is helpful as the platform adapts to new research needs (e.g., adding a new sensor type or data field).

PostgreSQL underlies the system as a tried-and-true relational database. We store experimental metadata, user collaboration information, and processed results in PostgreSQL, leveraging its reliability and strong ACID guarantees. For time-series sensor data, while much of it flows into our analytics pipeline (discussed in the following article), Postgres still maintains references and summaries that link to experiments or genetic datasets. Its support for JSONB also provides flexibility for storing semi-structured data, such as complex sensor calibration settings or analysis outputs, without compromising query performance on the structured parts.

Overall, the backend choices – NestJS, Zod, Drizzle, PostgreSQL – work in concert to create a resilient, high-quality API. They minimize runtime errors, enforce contracts (types and schemas) between services, and scale from day one (NestJS is built for enterprise scale, and PostgreSQL can handle large volumes of data). This means developers can create new features (or external integrations) on top of openJII with confidence, and scientists can trust the platform to handle their valuable data correctly.

Architecture in Action: Serving Researchers’ Needs

What does this stack enable? For one, real-time collaboration and data management for photosynthesis research. A researcher can design an experiment on the platform (using the web UI), set up their IoT sensors to stream data, and watch data points appear on their dashboard in real time. The NestJS backend and the event-driven pipeline (see next article) ensure that, as soon as a measurement arrives, it’s validated and stored, and that relevant calculations (e.g., aggregating photosynthesis metrics) are performed. Next.js streams updates to the UI so the researcher might literally see a curve of photosynthetic rate vs. time being drawn as the sun rises in their test plot.

At the same time, colleagues across the globe can log into openJII to collaborate. They might attach notes to an ongoing experiment or suggest protocol adjustments. The platform’s architecture supports this multi-user interaction by design. We built role-based access control and project collaboration features into the NestJS backend, enabling fine-grained permissions (with Zod ensuring no one can, say, accidentally enter an invalid role). The frontend uses these APIs to show appropriate controls – for example, a lab lead can invite a new member to a project, and the system will send out an invite and set the correct permissions.

Finally, it’s important to highlight that everything described above is open-source. The entire codebase is available in the openJII GitHub repository (GPL-3.0 licensed). This means researchers and developers are free to inspect how each feature is implemented, suggest improvements, or even deploy their own instance. The open-source architecture not only builds trust (users can see how data is handled) but also encourages community contributions – if someone needs a new analysis tool, they could implement it and propose it upstream. We’ve provided a comprehensive Developer Guide and documentation hub to make this as straightforward as possible[8].

In the next installment of our openJII launch series, we will explore the cloud infrastructure and data pipeline that power this architecture – including how we handle IoT sensor streams, our use of AWS and Databricks, and the “medallion” data architecture enabling reproducible science.


[1] [2] [3] [4] [5] [6] [7] [8] GitHub - Jan-IngenHousz-Institute/open-jii: OpenJII is an open-source platform for analyzing photosynthesis data from IoT and manual sensors, enabling real-time processing and visualization for plant science research.