diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,5 @@
+## [_Unreleased_](https://github.com/freckle/freckle-app/compare/freckle-prelude-v0.0.0.0...main)
+
+## [v0.0.0.0](https://github.com/freckle/freckle-app/tree/freckle-prelude-v0.0.0.0/freckle-prelude)
+
+First release, sprouted from `freckle-app-1.20.0.1`.
diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2022-2024 Renaissance Learning Inc
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/README.md b/README.md
new file mode 100644
--- /dev/null
+++ b/README.md
@@ -0,0 +1,7 @@
+# freckle-prelude
+
+Standard prelude for Freckle applications.
+
+---
+
+[CHANGELOG](./CHANGELOG.md) | [LICENSE](./LICENSE)
diff --git a/freckle-prelude.cabal b/freckle-prelude.cabal
new file mode 100644
--- /dev/null
+++ b/freckle-prelude.cabal
@@ -0,0 +1,56 @@
+cabal-version:      1.18
+name:               freckle-prelude
+version:            0.0.1.1
+license:            MIT
+license-file:       LICENSE
+maintainer:         Freckle Education
+homepage:           https://github.com/freckle/freckle-app#readme
+bug-reports:        https://github.com/freckle/freckle-app/issues
+synopsis:           Standard prelude for Freckle applications
+description:        Please see README.md
+category:           Prelude
+build-type:         Simple
+extra-source-files: package.yaml
+extra-doc-files:
+    README.md
+    CHANGELOG.md
+
+source-repository head
+    type:     git
+    location: https://github.com/freckle/freckle-app
+
+library
+    exposed-modules:    Freckle.App.Prelude
+    hs-source-dirs:     library
+    other-modules:      Paths_freckle_prelude
+    default-language:   GHC2021
+    default-extensions:
+        DataKinds DeriveAnyClass DerivingVia DerivingStrategies GADTs
+        LambdaCase NoImplicitPrelude NoMonomorphismRestriction
+        OverloadedStrings TypeFamilies
+
+    ghc-options:
+        -fignore-optim-changes -fwrite-ide-info -Weverything
+        -Wno-all-missed-specialisations -Wno-missing-exported-signatures
+        -Wno-missing-import-lists -Wno-missing-kind-signatures
+        -Wno-missing-local-signatures -Wno-missing-safe-haskell-mode
+        -Wno-monomorphism-restriction -Wno-prepositive-qualified-module
+        -Wno-safe -Wno-unsafe
+
+    build-depends:
+        base >=4.16.4.0 && <5,
+        containers >=0.6.5.1,
+        freckle-exception >=0.0.0.0,
+        hashable >=1.4.2.0,
+        mtl >=2.2.2,
+        primitive >=0.7.3.0,
+        safe >=0.3.19,
+        semigroupoids >=5.3.7,
+        text >=1.2.5.0,
+        time >=1.11.1.1,
+        unordered-containers >=0.2.19.1,
+        vector >=0.12.3.1
+
+    if impl(ghc >=9.8)
+        ghc-options:
+            -Wno-missing-role-annotations -Wno-missing-poly-kind-signatures
diff --git a/library/Freckle/App/Prelude.hs b/library/Freckle/App/Prelude.hs
new file mode 100644
--- /dev/null
+++ b/library/Freckle/App/Prelude.hs
@@ -0,0 +1,185 @@
+{-# LANGUAGE CPP #-}
+
+-- | Those functions and types we can't do without!
+module Freckle.App.Prelude
+  ( module Prelude
+
+    -- * Commonly imported types
+  , Alternative
+  , Generic
+  , HasCallStack
+  , Hashable
+  , HashMap
+  , HashSet
+  , Int64
+  , Map
+  , MonadIO
+  , MonadReader
+  , MonadUnliftIO
+  , NominalDiffTime
+  , NonEmpty
+  , PrimMonad
+  , ReaderT
+  , Set
+  , Text
+  , UTCTime
+  , Vector
+
+    -- * Commonly used functions
+
+    -- ** Lifts
+  , lift
+  , liftIO
+
+    -- ** 'Text'
+  , tshow
+  , pack
+  , unpack
+  , encodeUtf8
+  , decodeUtf8
+
+    -- ** 'Maybe'
+  , catMaybes
+  , fromMaybe
+  , isJust
+  , isNothing
+  , listToMaybe
+  , mapMaybe
+  , maybeToList
+
+    -- ** Safe alternatives to partial prelude functions (e.g. 'headMay')
+  , module SafeAlternatives
+
+    -- ** 'Either'
+  , partitionEithers
+
+    -- ** 'Foldable'
+  , module Foldable
+
+    -- ** 'Traversable'
+  , module Traversable
+
+    -- ** 'Functor'
+  , (<$$>)
+
+    -- ** 'Bifunctor'
+  , bimap
+  , first
+  , second
+
+    -- ** 'Applicative'
+  , (<|>)
+  , liftA2
+  , optional
+
+    -- ** 'Monad'
+  , (<=<)
+  , (>=>)
+  , guard
+  , join
+  , unless
+  , void
+  , when
+
+    -- ** 'Arrow'
+  , (&&&)
+  , (***)
+
+    -- ** 'UTCTime'
+  , getCurrentTime
+
+    -- * Exceptions
+  , throwM
+  , throwString
+  , fromJustNoteM
+  , catch
+  , catchJust
+  , catches
+  , try
+  , tryJust
+  , impossible
+  , ExceptionHandler (..)
+  , Exception (displayException)
+  , SomeException (..)
+  ) where
+
+-- Use 'Prelude' as the starting point, removing common partial functions
+
+import Prelude hiding
+  ( cycle
+  , foldl1
+  , foldr1
+  , head
+  , init
+  , last
+#if MIN_VERSION_base(4,18,0)
+  , liftA2
+#endif
+  , maximum
+  , minimum
+  , read
+  , tail
+  , (!!)
+  )
+
+-- Commonly used types (and their commonly used functions)
+
+import Control.Applicative (Alternative, liftA2, optional, (<|>))
+import Control.Monad.IO.Class (liftIO)
+import Control.Monad.Primitive (PrimMonad)
+import Control.Monad.Reader (MonadReader, ReaderT)
+import Data.HashMap.Strict (HashMap)
+import Data.HashSet (HashSet)
+import Data.Hashable (Hashable)
+import Data.Int (Int64)
+import Data.List.NonEmpty (NonEmpty)
+import Data.Map.Strict (Map)
+import Data.Set (Set)
+import Data.Text (Text, pack, unpack)
+import Data.Time (NominalDiffTime, UTCTime, getCurrentTime)
+import Data.Vector (Vector)
+import Freckle.App.Exception
+import GHC.Generics (Generic)
+
+-- Safe alternatives to prelude functions
+
+import Data.Semigroup.Foldable as SafeAlternatives (fold1, foldMap1)
+import Safe as SafeAlternatives
+  ( atMay
+  , cycleMay
+  , headMay
+  , initMay
+  , lastMay
+  , maximumMay
+  , minimumMay
+  , readMay
+  , tailMay
+  )
+
+-- Commonly used functions
+
+import Control.Arrow ((&&&), (***))
+import Control.Monad (guard, join, unless, void, when, (<=<), (>=>))
+import Control.Monad.Trans (lift)
+import Data.Bifunctor (bimap, first, second)
+import Data.Either (partitionEithers)
+import Data.Foldable as Foldable hiding (foldl1, foldr1)
+import Data.Maybe
+  ( catMaybes
+  , fromMaybe
+  , isJust
+  , isNothing
+  , listToMaybe
+  , mapMaybe
+  , maybeToList
+  )
+import Data.Text.Encoding (decodeUtf8, encodeUtf8)
+import Data.Traversable as Traversable
+
+infixl 4 <$$>
+(<$$>) :: (Functor c, Functor d) => (a -> b) -> c (d a) -> c (d b)
+f <$$> as = (f <$>) <$> as
+
+-- | 'Show' as 'Text'
+tshow :: Show a => a -> Text
+tshow = pack . show
diff --git a/package.yaml b/package.yaml
new file mode 100644
--- /dev/null
+++ b/package.yaml
@@ -0,0 +1,67 @@
+name: freckle-prelude
+version: 0.0.1.1
+maintainer: Freckle Education
+category: Prelude
+github: freckle/freckle-app
+synopsis: Standard prelude for Freckle applications
+description: Please see README.md
+
+extra-doc-files:
+  - README.md
+  - CHANGELOG.md
+
+extra-source-files:
+  - package.yaml
+
+language: GHC2021
+
+ghc-options:
+  - -fignore-optim-changes
+  - -fwrite-ide-info
+  - -Weverything
+  - -Wno-all-missed-specialisations
+  - -Wno-missing-exported-signatures # re-enables missing-signatures
+  - -Wno-missing-import-lists
+  - -Wno-missing-kind-signatures
+  - -Wno-missing-local-signatures
+  - -Wno-missing-safe-haskell-mode
+  - -Wno-monomorphism-restriction
+  - -Wno-prepositive-qualified-module
+  - -Wno-safe
+  - -Wno-unsafe
+
+when:
+  - condition: "impl(ghc >= 9.8)"
+    ghc-options:
+      - -Wno-missing-role-annotations
+      - -Wno-missing-poly-kind-signatures
+
+dependencies:
+  - base < 5
+
+default-extensions:
+  - DataKinds
+  - DeriveAnyClass
+  - DerivingVia
+  - DerivingStrategies
+  - GADTs
+  - LambdaCase
+  - NoImplicitPrelude
+  - NoMonomorphismRestriction
+  - OverloadedStrings
+  - TypeFamilies
+
+library:
+  source-dirs: library
+  dependencies:
+    - containers
+    - freckle-exception
+    - hashable
+    - mtl
+    - primitive
+    - safe
+    - semigroupoids
+    - text
+    - time
+    - unordered-containers
+    - vector
