diff --git a/.github/workflows/meta.yml b/.github/workflows/meta.yml
index cd00d820a7..ce97486950 100644
--- a/.github/workflows/meta.yml
+++ b/.github/workflows/meta.yml
@@ -4,17 +4,17 @@ on:
   # On push, only run if any of the metapackage files has changed
   push:
     paths:
-      - 'src/*meta*.f90'  
+      - 'src/*meta*.f90'
       - 'src/fpm/*meta*.f90'
       - 'src/fpm/manifest/*meta*.f90'
       - 'src/ci/meta_tests.sh'
       - 'src/.github/workflows/meta.yml'
-  # Always run on PR or release 
+  # Always run on PR or release
   pull_request:
   release:
     types: [published]
   # Allow manual triggering
-  workflow_dispatch:  
+  workflow_dispatch:
 
 env:
   CI: "ON" # We can detect this in the build system and other vendors implement it
@@ -51,7 +51,7 @@ jobs:
 
     - name: (Ubuntu/macOS) setup gcc version
       if: contains(matrix.os,'ubuntu') || contains(matrix.os,'macos')
-      run: |      
+      run: |
         echo "GCC_V=14" >> $GITHUB_ENV
 
     - name: (Windows) Install MSYS2
@@ -67,6 +67,8 @@ jobs:
           unzip
           curl
           hdf5
+          netcdf
+          netcdf-fortran
 
     - name: (Windows) Setup VS Build environment
       if: contains(matrix.os,'windows') && contains(matrix.mpi,'intel')
@@ -84,7 +86,7 @@ jobs:
         Remove-Item "oneAPI" -Force -Recurse
 
     - name: (Ubuntu) Install gfortran
-      if: contains(matrix.os,'ubuntu') 
+      if: contains(matrix.os,'ubuntu')
       run: |
         sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-${GCC_V} 100 \
         --slave /usr/bin/gfortran gfortran /usr/bin/gfortran-${GCC_V} \
@@ -94,13 +96,15 @@ jobs:
       if: contains(matrix.os,'ubuntu') && contains(matrix.mpi,'openmpi')
       run: |
         sudo apt-get update
-        sudo apt install -y -q openmpi-bin libopenmpi-dev hwloc fabric libhdf5-dev libhdf5-fortran-102
+        sudo apt install -y -q openmpi-bin libopenmpi-dev hwloc fabric libhdf5-dev \
+          libhdf5-fortran-102 libnetcdf-dev libnetcdff-dev
 
     - name: (Ubuntu) Install MPICH
       if: contains(matrix.os,'ubuntu') && contains(matrix.mpi,'mpich')
       run: |
         sudo apt-get update
-        sudo apt install -y -q mpich hwloc fabric libhdf5-dev libhdf5-fortran-102
+        sudo apt install -y -q mpich hwloc fabric libhdf5-dev libhdf5-fortran-102 \
+          libnetcdf-dev libnetcdff-dev
 
     - name: (Ubuntu) Retrieve Intel toolchain
       if: contains(matrix.os,'ubuntu') && contains(matrix.mpi,'intel')
@@ -115,16 +119,16 @@ jobs:
       uses: fortran-lang/setup-fortran@v1.6.1
       id: setup-fortran
       with:
-        compiler: intel 
-        version: 2024.1.0 
+        compiler: intel
+        version: 2024.1.0
 
-    - name: (Ubuntu) finalize oneAPI environment 
+    - name: (Ubuntu) finalize oneAPI environment
       if: contains(matrix.os,'ubuntu') && contains(matrix.mpi,'intel')
       run: |
         # Install MPI
-        sudo apt-get install -y -q intel-oneapi-mpi-devel ninja-build cmake
+        sudo apt-get install -y -q intel-oneapi-mpi-devel ninja-build cmake libcurl4-gnutls-dev
         source /opt/intel/oneapi/setvars.sh --force
-        printenv >> $GITHUB_ENV        
+        printenv >> $GITHUB_ENV
         # To run HDF5 with oneAPI, we need to build it from source. Use CMake to generate pkg-config info
         curl -O -L https://github.com/HDFGroup/hdf5/archive/refs/tags/snapshot-1.14.tar.gz
         tar zxf snapshot-1.14.tar.gz
@@ -133,6 +137,17 @@ jobs:
         cd build
         make -j
         sudo make install
+        curl -L https://github.com/Unidata/netcdf-c/archive/refs/tags/v4.9.2.tar.gz -o - | tar xz
+        cd netcdf-c-4.9.2
+        CC=icx CXX=icpx FC=ifx ./configure --prefix=/usr --with-hdf5=/usr
+        CC=icx CXX=icpx FC=ifx make -j
+        sudo make install
+        curl -L https://github.com/Unidata/netcdf-fortran/archive/refs/tags/v4.6.1.tar.gz -o - | tar xz
+        cd netcdf-fortran-4.6.1
+        cmake -B build -DCMAKE_Fortran_COMPILER=ifx -DCMAKE_C_COMPILER=icx -DCMAKE_CXX_COMPILER=icpx -DCMAKE_INSTALL_PREFIX=/usr
+        cd build
+        make -j
+        sudo make install
 
     - name: (Windows) Put MSYS2_MinGW64 on PATH
       if: contains(matrix.os,'windows') && (!contains(matrix.mpi,'intel'))
@@ -214,8 +229,14 @@ jobs:
 
     - name: (macOS) Install homebrew HDF5
       if: contains(matrix.os,'macos')
-      run: | 
-        brew install hdf5 
+      run: |
+        brew install hdf5
+
+    - name: (macOS) Install homebrew NetCDF
+      if: contains(matrix.os,'macos')
+      run: |
+        brew install netcdf
+        brew install netcdf-fortran
 
     # Phase 1: Bootstrap fpm with existing version
     - name: Install fpm
diff --git a/ci/meta_tests.sh b/ci/meta_tests.sh
index d9749bb511..3d55cf07ac 100755
--- a/ci/meta_tests.sh
+++ b/ci/meta_tests.sh
@@ -33,17 +33,22 @@ pushd metapackage_minpack
 popd
 
 pushd metapackage_mpi
-"$fpm" build --verbose 
+"$fpm" build --verbose
 "$fpm" run --verbose
 popd
 
 pushd metapackage_mpi_c
-"$fpm" build --verbose 
+"$fpm" build --verbose
 "$fpm" run --verbose
 popd
 
 pushd metapackage_hdf5
-"$fpm" build --verbose 
+"$fpm" build --verbose
+"$fpm" run --verbose
+popd
+
+pushd metapackage_netcdf
+"$fpm" build --verbose
 "$fpm" run --verbose
 popd
 
diff --git a/example_packages/metapackage_netcdf/app/main.f90 b/example_packages/metapackage_netcdf/app/main.f90
new file mode 100644
index 0000000000..6e3a2d11e8
--- /dev/null
+++ b/example_packages/metapackage_netcdf/app/main.f90
@@ -0,0 +1,10 @@
+program metapackage_netcdf
+    use netcdf4_f03
+    implicit none
+
+    integer(c_int) :: ncid, retval
+
+    retval = nf_create("dummy.nc", NF_INMEMORY, ncid)
+    if (retval /= nf_noerr) error stop nf_strerror(retval)
+    stop 0
+end program metapackage_netcdf
diff --git a/example_packages/metapackage_netcdf/fpm.toml b/example_packages/metapackage_netcdf/fpm.toml
new file mode 100644
index 0000000000..f5fd4869d7
--- /dev/null
+++ b/example_packages/metapackage_netcdf/fpm.toml
@@ -0,0 +1,2 @@
+name = "metapackage_netcdf"
+dependencies.netcdf="*"
diff --git a/src/fpm/manifest/meta.f90 b/src/fpm/manifest/meta.f90
index 41bd113a99..b9f419be38 100644
--- a/src/fpm/manifest/meta.f90
+++ b/src/fpm/manifest/meta.f90
@@ -52,6 +52,9 @@ module fpm_manifest_metapackages
         !> HDF5
         type(metapackage_request_t) :: hdf5
 
+        !> NetCDF
+        type(metapackage_request_t) :: netcdf
+
     end type metapackage_config_t
 
 
@@ -203,6 +206,9 @@ subroutine new_meta_config(self, table, meta_allowed, error)
         call new_meta_request(self%hdf5, "hdf5", table, meta_allowed, error)
         if (allocated(error)) return
 
+        call new_meta_request(self%netcdf, "netcdf", table, meta_allowed, error)
+        if (allocated(error)) return
+
     end subroutine new_meta_config
 
     !> Check local schema for allowed entries
@@ -214,7 +220,7 @@ logical function is_meta_package(key)
         select case (key)
 
             !> Supported metapackages
-            case ("openmp","stdlib","mpi","minpack","hdf5")
+            case ("openmp","stdlib","mpi","minpack","hdf5","netcdf")
                 is_meta_package = .true.
 
             case default
diff --git a/src/fpm_meta.f90 b/src/fpm_meta.f90
index 6d5f6a46ce..d52284aecd 100644
--- a/src/fpm_meta.f90
+++ b/src/fpm_meta.f90
@@ -30,6 +30,7 @@ module fpm_meta
     use fpm_meta_minpack, only: init_minpack
     use fpm_meta_mpi, only: init_mpi
     use fpm_meta_hdf5, only: init_hdf5
+    use fpm_meta_netcdf, only: init_netcdf
 
     use shlex_module, only: shlex_split => split
     use regex_module, only: regex
@@ -61,6 +62,7 @@ subroutine init_from_name(this,name,compiler,error)
             case("minpack"); call init_minpack(this,compiler,error)
             case("mpi");     call init_mpi    (this,compiler,error)
             case("hdf5");    call init_hdf5   (this,compiler,error)
+            case("netcdf");  call init_netcdf (this,compiler,error)
             case default
                 call syntax_error(error, "Package "//name//" is not supported in [metapackages]")
                 return
@@ -153,6 +155,12 @@ subroutine resolve_metapackage_model(model,package,settings,error)
             if (allocated(error)) return
         endif
 
+        ! netcdf
+        if (package%meta%netcdf%on) then
+            call add_metapackage_model(model,package,settings,"netcdf",error)
+            if (allocated(error)) return
+        endif
+
     end subroutine resolve_metapackage_model
 
 end module fpm_meta
diff --git a/src/metapackage/fpm_meta_netcdf.f90 b/src/metapackage/fpm_meta_netcdf.f90
new file mode 100644
index 0000000000..d28209e383
--- /dev/null
+++ b/src/metapackage/fpm_meta_netcdf.f90
@@ -0,0 +1,66 @@
+module fpm_meta_netcdf
+    use fpm_compiler, only: compiler_t, get_include_flag
+    use fpm_meta_base, only: metapackage_t, destroy
+    use fpm_meta_util, only: add_pkg_config_compile_options
+    use fpm_pkg_config, only: assert_pkg_config, pkgcfg_has_package
+    use fpm_strings, only: string_t
+    use fpm_error, only: error_t, fatal_error
+
+    implicit none
+
+    private
+
+    public :: init_netcdf
+
+contains
+
+    !> Initialize NetCDF metapackage for the current system
+    subroutine init_netcdf(this, compiler, error)
+        class(metapackage_t), intent(inout) :: this
+        type(compiler_t), intent(in) :: compiler
+        type(error_t), allocatable, intent(out) :: error
+
+        logical :: s
+        character(len=:), allocatable :: include_flag, libdir
+
+        include_flag = get_include_flag(compiler, "")
+
+        !> Cleanup
+        call destroy(this)
+        allocate (this % link_libs(0), this % incl_dirs(0), this % external_modules(0))
+        this % link_flags = string_t("")
+        this % flags = string_t("")
+
+        !> Assert pkg-config is installed
+        if (.not. assert_pkg_config()) then
+            call fatal_error(error, 'netcdf metapackage requires pkg-config')
+            return
+        end if
+
+        if (.not. pkgcfg_has_package('netcdf')) then
+            call fatal_error(error, 'pkg-config could not find a suitable netcdf package.')
+        end if
+        call add_pkg_config_compile_options(this, 'netcdf', include_flag, libdir, error)
+        if (allocated(error)) return
+
+        if (.not. pkgcfg_has_package('netcdf-fortran')) then
+            call fatal_error(error, &
+                             'pkg-config could not find a suitable netcdf-fortran package.')
+        end if
+        call add_pkg_config_compile_options(this, 'netcdf-fortran', include_flag, libdir, error)
+        if (allocated(error)) return
+
+        !> Add NetCDF modules as external
+        this % has_external_modules = .true.
+        this % external_modules = [string_t('netcdf'), &
+                                   string_t('netcdf4_f03'), &
+                                   string_t('netcdf4_nc_interfaces'), &
+                                   string_t('netcdf4_nf_interfaces'), &
+                                   string_t('netcdf_f03'), &
+                                   string_t('netcdf_fortv2_c_interfaces'), &
+                                   string_t('netcdf_nc_data'), &
+                                   string_t('netcdf_nc_interfaces'), &
+                                   string_t('netcdf_nf_data'), &
+                                   string_t('netcdf_nf_interfaces')]
+    end subroutine init_netcdf
+end module fpm_meta_netcdf