Back to Home
NetPad

Why NetPad?

Stop rebuilding forms, workflows, and data management from scratch.

Ship production-ready applications in hours instead of weeks. Focus on what makes your app unique, not boilerplate infrastructure.

10x

Faster Development

90%

Less Code

100%

Type Safe

See the Difference

Building an employee onboarding form with multi-page wizard, conditional logic, and nested data
Without NetPad
~2000 lines
// form-components/TextField.tsx (1 of 15+ components)
import { useState, useEffect } from 'react';

interface TextFieldProps {
  label: string;
  value: string;
  onChange: (value: string) => void;
  error?: string;
  required?: boolean;
  placeholder?: string;
  disabled?: boolean;
  minLength?: number;
  maxLength?: number;
  pattern?: RegExp;
  helpText?: string;
}

export function TextField({
  label, value, onChange, error, required,
  placeholder, disabled, minLength, maxLength,
  pattern, helpText
}: TextFieldProps) {
  const [touched, setTouched] = useState(false);
  const [localError, setLocalError] = useState<string>();

  useEffect(() => {
    if (!touched) return;
    if (required && !value) {
      setLocalError(`${label} is required`);
    } else if (minLength && value.length < minLength) {
      setLocalError(`Min ${minLength} characters`);
    } else if (maxLength && value.length > maxLength) {
      setLocalError(`Max ${maxLength} characters`);
    } else if (pattern && !pattern.test(value)) {
      setLocalError('Invalid format');
    } else {
      setLocalError(undefined);
    }
  }, [value, touched, required, minLength, maxLength]);

  return (
    <div className="form-field">
      <label>{label}{required && '*'}</label>
      <input
        type="text"
        value={value}
        onChange={(e) => onChange(e.target.value)}
        onBlur={() => setTouched(true)}
        placeholder={placeholder}
        disabled={disabled}
      />
      {helpText && <span className="help">{helpText}</span>}
      {(error || localError) && (
        <span className="error">{error || localError}</span>
      )}
    </div>
  );
}

// Repeat for: EmailField, PhoneField, SelectField,
// DateField, CheckboxField, RadioField, TextArea,
// NumberField, SliderField, RatingField, FileUpload,
// AutocompleteField, TagsField, SwitchField...

// form-logic/useMultiPageForm.ts
export function useMultiPageForm(config) {
  const [currentPage, setCurrentPage] = useState(0);
  const [formData, setFormData] = useState({});
  const [errors, setErrors] = useState({});
  const [visited, setVisited] = useState(new Set());

  const validatePage = (pageIndex: number) => {
    const pageFields = config.pages[pageIndex].fields;
    const pageErrors = {};
    // ... 50+ lines of validation logic
  };

  const nextPage = () => {
    if (validatePage(currentPage)) {
      setCurrentPage(prev => prev + 1);
    }
  };

  // ... 100+ more lines for prev, submit, etc.
}

// form-logic/conditionalLogic.ts
export function evaluateConditions(conditions, data) {
  // ... 80+ lines of condition evaluation
}

// form-logic/nestedData.ts
export function setNestedValue(obj, path, value) {
  // ... 40+ lines of nested object handling
}

// Plus: API routes, database schemas, error handling,
// accessibility, testing, documentation...

// Total: 2000+ lines across 20+ files
// Time: 2-4 weeks of development
With NetPad
~80 lines
// app/onboarding/page.tsx - THE ENTIRE FORM
import { FormRenderer, FormConfiguration } from '@netpad/forms';

const onboardingForm: FormConfiguration = {
  name: 'Employee Onboarding',
  fieldConfigs: [
    {
      path: 'firstName',
      label: 'First Name',
      type: 'short_text',
      included: true,
      required: true,
      fieldWidth: 'half',
    },
    {
      path: 'email',
      label: 'Email',
      type: 'email',
      included: true,
      required: true,
    },
    {
      path: 'department',
      label: 'Department',
      type: 'dropdown',
      included: true,
      options: [
        { label: 'Engineering', value: 'eng' },
        { label: 'Marketing', value: 'mkt' },
      ],
    },
    {
      path: 'officeLocation',
      label: 'Office',
      type: 'dropdown',
      included: true,
      conditionalLogic: {
        action: 'show',
        conditions: [
          { field: 'workType', operator: 'equals', value: 'hybrid' }
        ],
      },
    },
    {
      path: 'emergencyContact.name',
      label: 'Emergency Contact',
      type: 'short_text',
      included: true,
    },
    {
      path: 'emergencyContact.phone',
      label: 'Contact Phone',
      type: 'phone',
      included: true,
    },
  ],
  multiPage: {
    enabled: true,
    showProgressBar: true,
    pages: [
      { id: 'personal', title: 'Personal', fields: ['firstName', 'email'] },
      { id: 'work', title: 'Employment', fields: ['department', 'officeLocation'] },
      { id: 'emergency', title: 'Emergency', fields: ['emergencyContact.name', 'emergencyContact.phone'] },
    ],
  },
};

export default function OnboardingPage() {
  const handleSubmit = async (data) => {
    await fetch('/api/onboarding', {
      method: 'POST',
      body: JSON.stringify(data),
    });
  };

  return <FormRenderer config={onboardingForm} onSubmit={handleSubmit} />;
}

// That's it. ~80 lines. Ships today.
96% less code • Ships in hours, not weeks

Feature-by-Feature Comparison

What you'd need to build vs. what NetPad provides
FeatureBuild From ScratchWith NetPad
Text, Email, Phone fields
3 components (~150 lines)
Built-in
Date/Time pickers
2 components + library
Built-in
Dropdowns, Radio, Checkbox
3 components (~200 lines)
Built-in
File upload
1 component + S3 setup
Built-in
Multi-page wizard
Custom state machine (~300 lines)
5 lines of config
Progress indicator
Custom component (~100 lines)
1 boolean flag
Field validation
Per-field + form-level (~200 lines)
Declarative config
Conditional logic
Custom evaluator (~150 lines)
JSON conditions
Nested data (contact.phone)
Utility functions (~80 lines)
Dot notation
Computed fields
Custom formula parser
Formula strings
Error display
Custom error handling
Automatic
Accessibility (ARIA)
Manual implementation
Built-in

The Three Pillars of NetPad

Forms, Workflows, and Data Management — all integrated
Forms
Without NetPad (2-3 weeks)
  • Build 15+ field components

  • Implement validation logic

  • Handle conditional visibility

  • Manage multi-page state

  • Style everything from scratch


With NetPad (2-3 hours)
  • 28+ field types included

  • Declarative validation

  • JSON-based conditions

  • Config-driven wizards

  • Themeable out of the box

Workflows
Without NetPad (3-4 weeks)
  • Design state machine

  • Build approval chains

  • Implement notifications

  • Handle edge cases

  • Add audit logging


With NetPad (1-2 days)
  • Visual workflow builder

  • Pre-built approval patterns

  • Email/Slack integration

  • Automatic retries

  • Built-in audit trail

Data Management
Without NetPad (2-3 weeks)
  • Design database schema

  • Build CRUD APIs

  • Implement search/filter

  • Add pagination

  • Build admin dashboard


With NetPad (Included)
  • Automatic MongoDB storage

  • REST API included

  • Full-text search

  • Built-in pagination

  • Admin dashboard ready

The Bottom Line

Building From Scratch

6-10 weeks

Forms + Workflows + Data Management

5,000+ lines of code

Ongoing maintenance burden

With NetPad

1-2 days

All three capabilities integrated

~100 lines of configuration

Maintained by NetPad team

Start BuildingView on GitHub

Free MongoDB Atlas cluster included. No credit card required.

Get Started Your Way

Use the hosted platform or integrate forms and workflows directly into your apps
npm package
@netpad/forms

Install the npm package and render NetPad forms directly in your React applications. Perfect for custom integrations and embedded forms.

$ npm install @netpad/forms

28+ Field Types
Multi-page Wizards
Conditional Logic
TypeScript
View on npm
npm package
@netpad/workflows

Trigger and manage workflow executions programmatically from your backend services, cron jobs, or CI/CD pipelines.

$ npm install @netpad/workflows

Execute Workflows
Wait for Completion
Lifecycle Control
TypeScript
View on npm
Example App
Employee Onboarding

Clone a complete working example with a 3-page wizard, conditional fields, nested data structures, and validation — all in under 300 lines of code.

$ git clone examples/employee-onboarding-demo

3-Page Wizard
Progress Tracking
Nested Objects
Next.js 14
View Example
NetPad

NetPad — The Complete MongoDB Data Platform