diff --git a/Changelog.md b/Changelog.md
new file mode 100644
--- /dev/null
+++ b/Changelog.md
@@ -0,0 +1,4 @@
+### 0.1.0.0
+
+- Initial version.
+
diff --git a/GhcStdin.hs b/GhcStdin.hs
new file mode 100644
--- /dev/null
+++ b/GhcStdin.hs
@@ -0,0 +1,83 @@
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  GhcStdin
+-- Copyright   :  (c) Alexey Radkov 2022
+-- License     :  BSD-style
+--
+-- Maintainer  :  alexey.radkov@gmail.com
+-- Stability   :  experimental
+-- Portability :  non-portable (requires GHC with support of plugins)
+--
+-- A frontend plugin for GHC to compile source code from the standard input.
+--
+-----------------------------------------------------------------------------
+
+
+module GhcStdin (frontendPlugin) where
+
+import GHC.Paths
+#if MIN_VERSION_ghc(9,0,2)
+import GHC.Plugins
+#else
+import GhcPlugins
+#endif
+import Control.Monad
+import System.IO
+import System.IO.Temp
+import System.Process
+import System.Exit
+
+-- | Frontend plugin for GHC to compile source code from the standard input.
+--
+-- In GHC, it is not possible to read source code from the standard input.
+--
+-- @
+-- __$__ echo \'module Main where main = putStrLn \"Ok\"\' | ghc -o simple_ok
+-- ghc-9.2.3: no input files
+-- Usage: For basic information, try the \`--help\' option.
+-- @
+--
+-- This plugin makes this possible.
+--
+-- @
+-- __$__ echo \'module Main where main = putStrLn \"Ok\"\' | ghc __/--frontend GhcStdin/__ /-ffrontend-opt=\"-o simple_ok\"/
+-- [1 of 1] Compiling Main             ( ghc-stdin-d8c31cf0ed893d79\/ghc-stdin260612-0.hs, ghc-stdin-d8c31cf0ed893d79\/ghc-stdin260612-0.o )
+-- Linking simple_ok ...
+-- __$__ ./simple_ok
+-- Ok
+-- @
+--
+-- Notice that GHC flags are passed via /-ffrontend-opt/ in a single string.
+--
+-- Another use case is collecting exported FFI C functions from a module and
+-- putting them in a new shared library.
+--
+-- @
+-- __$__ export NGX_MODULE_PATH=\/var\/lib\/nginx\/x86_64-linux-ghc-9.2.3
+-- __$__ echo \'module NgxHealthcheck where import NgxExport.Healthcheck ()\' | ghc __/--frontend GhcStdin/__ /-ffrontend-opt=\"-Wall -O2 -dynamic -shared -fPIC -lHSrts_thr-ghc$(ghc --numeric-version) -L$NGX_MODULE_PATH -lngx_healthcheck_plugin -o ngx_healthcheck.so\"/ 
+-- [1 of 1] Compiling NgxHealthcheck   ( ghc-stdin-74de48274545714b\/ghc-stdin266454-0.hs, ghc-stdin-74de48274545714b\/ghc-stdin266454-0.o )
+-- Linking ngx_healthcheck.so ...
+-- @
+--
+-- (this is a real-world example taken from
+-- [nginx-healthcheck-plugin](https://github.com/lyokha/nginx-healthcheck-plugin)).
+--
+-- Internally, the plugin creates a temporary directory with a temporary source
+-- file inside it with the contents read from the standard input. Then it spawns
+-- another GHC process to compile this file with options passed in
+-- /-ffrontend-opt/.
+frontendPlugin :: FrontendPlugin
+frontendPlugin = defaultFrontendPlugin { frontend = compileCodeFromStdin }
+
+compileCodeFromStdin :: FrontendPluginAction
+compileCodeFromStdin flags _ = liftIO $
+    withTempDirectory "." "ghc-stdin" $ \dir ->
+        withTempFile dir "ghc-stdin.hs" $ \src hsrc -> do
+            contents <- getContents
+            hPutStr hsrc contents >> hFlush hsrc
+            (_, _, _, h) <- createProcess $ proc ghc $ src : wordsOfHead flags
+            r <- waitForProcess h
+            unless (r == ExitSuccess) $ exitWith r
+    where wordsOfHead [] = []
+          wordsOfHead (x : _) = words x
+
diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,28 @@
+Copyright 2022 Alexey Radkov
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+1. Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+
+3. Neither the name of the copyright holder nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/README.md b/README.md
new file mode 100644
--- /dev/null
+++ b/README.md
@@ -0,0 +1,44 @@
+GHC frontend plugin GhcStdin
+============================
+
+[![Build Status](https://github.com/lyokha/ghc-stdin/workflows/CI/badge.svg)](https://github.com/lyokha/ghc-stdin/actions?query=workflow%3ACI)
+[![Hackage](https://img.shields.io/hackage/v/ghc-stdin.svg?label=hackage%20%7C%20ghc-stdin&logo=haskell&logoColor=%239580D1)](https://hackage.haskell.org/package/ghc-stdin)
+
+In GHC, it is not possible to read source code from the standard input.
+
+```ShellSession
+$ echo 'module Main where main = putStrLn "Ok"' | ghc -o simple_ok
+ghc-9.2.3: no input files
+Usage: For basic information, try the `--help' option.
+```
+
+This plugin makes this possible.
+
+```ShellSession
+$ echo 'module Main where main = putStrLn "Ok"' | ghc --frontend GhcStdin -ffrontend-opt="-o simple_ok"
+[1 of 1] Compiling Main             ( ghc-stdin-d8c31cf0ed893d79/ghc-stdin260612-0.hs, ghc-stdin-d8c31cf0ed893d79/ghc-stdin260612-0.o )
+Linking simple_ok ...
+$ ./simple_ok
+Ok
+```
+
+Notice that GHC flags are passed via *-ffrontend-opt* in a single string.
+
+Another use case is collecting exported FFI C functions from a module and
+putting them in a new shared library.
+
+```ShellSession
+$ export NGX_MODULE_PATH=/var/lib/nginx/x86_64-linux-ghc-9.2.3
+$ echo 'module NgxHealthcheck where import NgxExport.Healthcheck ()' | ghc --frontend GhcStdin -ffrontend-opt="-Wall -O2 -dynamic -shared -fPIC -lHSrts_thr-ghc$(ghc --numeric-version) -L$NGX_MODULE_PATH -lngx_healthcheck_plugin -o ngx_healthcheck.so" 
+[1 of 1] Compiling NgxHealthcheck   ( ghc-stdin-74de48274545714b/ghc-stdin266454-0.hs, ghc-stdin-74de48274545714b/ghc-stdin266454-0.o )
+Linking ngx_healthcheck.so ...
+```
+
+(this is a real-world example taken from
+[nginx-healthcheck-plugin](https://github.com/lyokha/nginx-healthcheck-plugin)).
+
+Internally, the plugin creates a temporary directory with a temporary source
+file inside it with the contents read from the standard input. Then it spawns
+another GHC process to compile this file with options passed in
+*-ffrontend-opt*.
+
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,3 @@
+import Distribution.Simple
+main = defaultMain
+
diff --git a/ghc-stdin.cabal b/ghc-stdin.cabal
new file mode 100644
--- /dev/null
+++ b/ghc-stdin.cabal
@@ -0,0 +1,33 @@
+name:                  ghc-stdin
+version:               0.1.0.0
+license:               BSD3
+license-file:          LICENSE
+extra-source-files:    Changelog.md, README.md
+author:                Alexey Radkov
+maintainer:            alexey.radkov@gmail.com
+synopsis:              Compile source code from the standard input
+description:           A frontend plugin for GHC to compile source code from
+                       the standard input.
+category:              Development
+bug-reports:           https://github.com/lyokha/ghc-stdin/issues
+build-type:            Simple
+cabal-version:         1.20
+
+source-repository head
+  type:                git
+  location:            https://github.com/lyokha/ghc-stdin
+
+library
+  default-language:    Haskell2010
+  build-depends:       base >= 4.11.0.0 && < 5,
+                       ghc >= 8.4.1,
+                       ghc-paths,
+                       temporary,
+                       process
+
+  exposed-modules:     GhcStdin
+
+  default-extensions:  CPP
+
+  ghc-options:        -Wall
+
